PDF Viewer in Business Central

22 Jan

Recently a question was raised by one of the MVP’s if somebody has an example of a PDF viewer in Business Central. That reminded me that I actually had an example, created almost one year ago. Should have published it way earlier! Anyway, I thought it still makes sense to polish that thing and share it.

I’ve explored several ways to display a PDF as part of a website. The HTML <object> element uses the native browser support for viewing PDF. Optionally, it can be combined with the HTML <iframe> object as a fallback. It doesn’t require any JavaScript and seems to work on most browsers.

However, the browser will use whichever PDF reader is installed on the system and there is no way to customize the look and feel. There is only a very limited set of API’s available and even these API’s are not supported in all browsers. In other words, how the PDF is rendered on the page is out of your control.

So I decided to move on and look for a solution that gives you full control over how the PDF is rendered, including an API to integrate with. And I stumbled over PDF.js, an open-source PDF viewer, built with HTML5 and supported by Mozilla Labs.

This tool proved to be very flexible and I got it to work pretty quickly. In the first place as a single page viewer, as explained in the examples. However, the option were still quite limited and I figured that it would be great to take the viewer, which has all the options you can think of, and embed that one into Business Central. Not just as-is, but integrated with Busines Central, and with a little re-skin applied, like they ask here: However, we do ask if you plan to embed the viewer in your own site, that it not just be an unmodified version. Please re-skin it or build upon it.

Allright, enough talking, let’s first look at the result and then see how it’s done.

And the same control can also be used in a factbox, without any modifications:

And now straight to the source code. The complete code can be found on GitHub: https://github.com/ajkauffmann/PDFViewer

Please read the explanation below how to use it, before you jump in and start using it right away!

The GitHub repository consists of two folders:

  • PDFViewer: Business Central extension
  • pdfjs-2.0.943-dist: source code for a static HTML website

If you clone the repo, then you will find a PDFViewer.code-workspace file in the root. Open this file with VS Code and you will find both folders opened at once. Alternatively, you can open the folders individually.

Let’s first look at the folder pdfjs-2.0.943-dist. This is a download of the latest version of the viewer application, which can be found here. Alternatively, you can clone the full repo on GitHub, with all source code and build the viewer yourself by using gulp. But if you are not used to that, it’s easier to download the distributable file of the viewer and use that one.

Embedding a JavaScript control add-in in Business Central is normally done by packaging all necessary files in the extension. This could potentially work, with the trick that Vjeko explained in this blog post. However, the viewer contains about 400 files, so you get a really big list of image resource in the controladdin. And what’s more, it just doesn’t work. Some files couldn’t be downloaded at all, like the .properties files in the locale folder and the bcmap files in the cmaps folder. On top of that, if it works in your local docker sandbox that doesn’t mean it will work with Business Central online. It’s out of scope to go into details about that, but it just didn’t work.

How can we embed a control add-in if the files can’t be published together with the extension? Simply, by hosting the files elsewhere and point the browser to those files. Like you can include JavaScript files from external sources, you can also include HTML files from external sources.

So I decided to just grab the whole PDF.js viewer application and host it on Azure. I have used static website hosting in Azure storage. This is an option with Azure storage with no additional cost. Azure blob storage is pretty cheap, so it was a no-brainer. With extra options like CDN and custom domain names it is even more attractive.

So this is what I did: after modifying the PDF web viewer application to integrate with Business Central (see below) I have created a static website with the Azure portal as explained here. Then I uploaded the files using the Azure Storage Explorer. I have now the PDF web viewer application hosted here: https://bcpdfviewer.z6.web.core.windows.net/web/viewer.html. As a result, the AL extension is pretty small and easy to understand.

Warning: don’t use my PDF web viewer website for any production scenario! Ue your own hosting website instead!

After I figured this hosting thing out, there were some other hurdles to take. I will save some of them for another blog post and just focus on the parts to integrate the web viewer application with Business Central. I will first go over the modifications I did to the web viewer application and then switch to the AL code.

Viewer.js

The web viewer app comes with a JavaScript file that configures the viewer and loads it into the page. Until the viewer is ready, we should not load anything into it. Because I couldn’t find any event that would tell me if the viewer is loaded, I decided to add a new event. You can find this in the viewer.js in the function webViewerLoad.

bcintegration.js

To integrate with Business Central and be able to send data to the viewer, I have created a new JavaScript file that is loaded together with the web viewer page. It contains functions to send the new event to Business Central and to load documents into the PDF viewer. It supports both URL and Base64 encoded data, so it is possible to use data from blob fields.

This bcintegration.js must be added to the viewer.html page.

viewer.css

The viewer.css defines the look and feel of the viewer. I’ve made a few changes to better integrate the viewer into Business Central. Feel free to play with it and change to whatever you like. Look at the history of the file to see what changes I did.

That’s it, let’s now have a look at the AL code

The most important part you need to understand is how exactly the web viewer is embedded in the page. The web viewer is loaded in a nested <iframe> element that is added to the control add-in element. This is done in script.js.

Because it is not possible to directly communicate between the iframe, which has a different url then the parent, and the parent object, the script.js file implements to use postMessage and onMessage. This is a safe way to communicate between the two and supported by all browsers.

In the top of the script.js file, the url of the website where the PDF web viewer is hosted is specified. You should change this to the website where you have hosted your version of the web viewer.

Don’t use a trailing slash for the url setting. It wil fail the test in the onMessage function.

The rest of the code is just tableextensions, pages and pageextensions to add the viewer to the Incoming Document pages. I guess you will be able to figure out yourself what’s going on there.

There are some tricks in this PDF viewer control add-in that I haven’t talked about yet. I will do that in a next blog post because these tricks apply to JavaScript control add-ins in general.

Thanks Mohana for raising the question and testing the first release!

Get luck with it and please let me know what you think! Feel free to grab the GitHub repository and to contribute to it if you have something cool to share.

9 thoughts on “PDF Viewer in Business Central

      • I created a very simple viewer from scratch with only prev/next buttons. So no problem to create a regular control-addin (and loading pdfjs from a cdn). But if you want to have a more full fledged viewer, your idea to host it elsewhere is a good idea.

  1. Pingback: Controlling the size of a Control Add-In - Kauffmann @ Dynamics NAV - Dynamics 365 Business Central/NAV User Group - Dynamics User Group

  2. Nice blog post – do you know how to control the width of such a PDF viewer if you place it on the factbox area?

    I would like to have a repeater list on left side, and PDF preview taking 1/3 of screen width, this is impossible with factbox default width.

    I tried so many things 🙂

Leave a Reply to ajk Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.