Building a PDF Preview feature inside Dynamics 365 CE with JScript

Tamilarasu Arunachalam
4 min readJan 27, 2024

--

Photo by dlxmedia.hu on Unsplash

I recently encountered a question regarding the possibility of previewing a PDF file inside Dynamics 365 CRM or a Model Driven App without opening an additional tab or window. After conducting some research, I found that there is no out-of-the-box (OOTB) feature for previewing PDF files. However, I devised an approach to achieve this by leveraging client-side scripting, specifically using JScript.

One of the methods I explored is the Xrm.Navigation.openFile(file, openFileOptions) script. This script allows you to open a file in another tab or window. However, the goal is to have the file open inline within the Unified Client Interface (UCI) page. More details on this script can be found in the Microsoft Docs.

To implement this, I created a file field on the Accounts Entity named “Test File” and added it to the main form. The preview feature is intended for files uploaded to this column.

To accomplish the preview functionality, I decided to create an HTML web resource and a JS web resource. The HTML web page serves as a canvas for previewing a PDF file inside it, while the JS web resource is designed to open a modal window inline, containing the web page for previewing the file.

The below is the HTML code

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Document</title>
<style>
canvas {
width: 100%;
}
</style>
<script src="https://mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script>
<script src="../WebResources/ClientGlobalContext.js.aspx" type="text/javascript"></script>
<script type="text/javascript">
var url = parent.window.location.href;

var dataIndex = url.lastIndexOf("=") + 1;
var dataLength = url.length;
var recordData = url.slice(dataIndex, dataLength);
var recordId = recordData.replace("%20", "").replace("%7b", "").replace("%7d", "");
var clientUrl = parent.Xrm.Utility.getGlobalContext() ? Xrm.Utility.getGlobalContext().getClientUrl() : null;

fetch(clientUrl + "/api/data/v9.2/accounts(" + recordId + ")/crf4c_uploadfile?$size=full").then(
Response => {
debugger;
Response.json().then(
data => {
if (data.value !== "") {
let urlData = data.value;
// convert base64 to binary
var binaryString = window.atob(urlData);
var binaryLen = binaryString.length;
var fileName = 'Test-File.pdf';
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
var filebyte = bytes;
// create a blob
var blob = new Blob([filebyte], { type: "application/pdf" }),
blobUrl = window.URL.createObjectURL(blob);
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
// open the new window with the blob url
// window.open(blobUrl, "_self");
// window.URL.revokeObjectURL(blobUrl);

var url = blobUrl;
var { pdfjsLib } = globalThis;

// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://mozilla.github.io/pdf.js/build/pdf.worker.mjs';

// Asynchronous download of PDF
var loadingTask = pdfjsLib.getDocument(url);
loadingTask.promise.then(function (pdf) {
console.log('PDF loaded');

// Fetch the first page
var pageNumber = 1;
pdf.getPage(pageNumber).then(function (page) {
console.log('Page loaded');

var scale = 1.5;
var viewport = page.getViewport({ scale: scale });

// Prepare canvas using PDF page dimensions
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;

// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function () {
console.log('Page rendered');
});
});
}, function (reason) {
// PDF loading error
console.error(reason);
});
}
}
}
);
}
);
</script>
</head>

<body>
<canvas id="the-canvas"></canvas>
</body>

</html>

And the below is the JScript code

function previewPdf(){
var pageInput = {
pageType: "webresource",
webresourceName: "crf4c_showFile"
};

var pageOptions = {
target: 2,
width: 800,
height: 600,
position: 1
};
// open a web resource inside a modal window
Xrm.Navigation.navigateTo(pageInput, pageOptions).then(
function success(result) {
console.log(result);
}, function error(error) {
console.log(error.message);
}
);
}

To call up the preview modal, I created a command button for the main form using the command editor and added the JavaScript web resource as an action. To render PDF files, I’ve integrated the PDF.js library. Alternatively, users can utilize their browser’s built-in PDF viewer for this purpose. Subsequently, I saved and published the changes.

Following these steps, go to the Accounts main form, upload any PDF file to the “Test File” field, and then click on the “Preview File” button in the Ribbon. This action should display the file opened inside the page.To demonstrate the implementation, I’ve attached a gif for your reference.

Have a great day!

Originally published at https://www.tamilarasu.me on January 27, 2024.

--

--

Tamilarasu Arunachalam

A Software Engineer with experience in developing applications out of Power Platform, majorly on Power Apps and Power Automate. I am a seasonal blogger too.