Implement WebViewer in Salesforce as a Lightning Web Component

This sample is demonstrating how to integrate the Apryse WebViewer into Salesforce as a Lightning Web Component. For more information, see this guide.

WebViewer provides a slick out-of-the-box responsive UI that enables you to view, annotate and manipulate PDFs and other document types inside any web project.

Click the button below to view the full project in GitHub.

1import getUser from '@salesforce/apex/Apryse_ContentVersionController.getUser';
2import saveDocument from '@salesforce/apex/Apryse_ContentVersionController.saveDocument';
3import libUrl from '@salesforce/resourceUrl/lib';
4import myfilesUrl from '@salesforce/resourceUrl/myfiles';
5import { fireEvent, registerListener, unregisterAllListeners } from 'c/pubsub';
6import { CurrentPageReference } from 'lightning/navigation';
7import { loadScript } from 'lightning/platformResourceLoader';
8import { api, LightningElement, wire } from 'lwc';
9import mimeTypes from './mimeTypes';
10
11function _base64ToArrayBuffer(base64) {
12 var binary_string = window.atob(base64);
13 var len = binary_string.length;
14 var bytes = new Uint8Array( len );
15 for (var i = 0; i < len; i++) {
16 bytes[i] = binary_string.charCodeAt(i);
17 }
18 return bytes.buffer;
19}
20
21export default class ApryseWvInstance extends LightningElement {
22 //initialization options
23 fullAPI = true;
24 enableRedaction = true;
25 enableFilePicker = true;
26
27 uiInitialized = false;
28
29 source = 'My file';
30 @api recordId;
31
32 @wire(CurrentPageReference)
33 pageRef;
34
35 username;
36
37 connectedCallback() {
38 registerListener('blobSelected', this.handleBlobSelected, this);
39 registerListener('closeDocument', this.closeDocument, this);
40 registerListener('downloadDocument', this.downloadDocument, this);
41 registerListener('fileSelected', this.handleFileSelected, this);
42 window.addEventListener('message', this.handleReceiveMessage.bind(this), false);
43 }
44
45 disconnectedCallback() {
46 unregisterAllListeners(this);
47 window.removeEventListener('message', this.handleReceiveMessage);
48 }
49
50 handleBlobSelected(record) {
51 const blobby = new Blob([_base64ToArrayBuffer(record.body)], {
52 type: mimeTypes[record.FileExtension]
53 });
54
55
56 const payload = {
57 blob: blobby,
58 extension: record.cv.FileExtension,
59 filename: record.cv.Title + "." + record.cv.FileExtension,
60 documentId: record.cv.Id
61 };
62
63 this.iframeWindow.postMessage({ type: 'OPEN_DOCUMENT_BLOB', payload }, '*');
64 }
65
66 renderedCallback() {
67 var self = this;
68
69 if (this.uiInitialized) {
70 return;
71 }
72
73 Promise.all([
74 loadScript(self, libUrl + '/webviewer.min.js')
75 ])
76 .then(() => this.handleInitWithCurrentUser())
77 .catch(console.error);
78 }
79
80 handleFileSelected(file) {
81 this.iframeWindow.postMessage({type: 'OPEN_DOCUMENT', file: file}, '*')
82 }
83
84 handleInitWithCurrentUser() {
85 getUser()
86 .then((result) => {
87 this.username = result;
88 this.error = undefined;
89
90 this.initUI();
91 })
92 .catch((error) => {
93 console.error(error);
94 this.showNotification('Error', error.body.message, 'error');
95 });
96 }
97
98 initUI() {
99 var myObj = {
100 libUrl: libUrl,
101 fullAPI: this.fullAPI || false,
102 namespacePrefix: '',
103 username: this.username,
104 };
105 var url = myfilesUrl + '/webviewer-demo-annotated.pdf';
106
107 const viewerElement = this.template.querySelector('div')
108 // eslint-disable-next-line no-unused-vars
109 const viewer = new WebViewer.Iframe({
110 path: libUrl, // path to the Apryse 'lib' folder on your server
111 custom: JSON.stringify(myObj),
112 backendType: 'ems',
113 config: myfilesUrl + '/config_apex.js',
114 fullAPI: this.fullAPI,
115 enableFilePicker: this.enableFilePicker,
116 enableRedaction: this.enableRedaction,
117 enableMeasurement: this.enableMeasurement,
118 enableOptimizedWorkers: true,
119 loadAsPDF: true,
120 // l: 'YOUR_LICENSE_KEY',
121 // To use spreadsheet editor feature, uncomment the below line and comment out loadAsPDF: true
122 // initialMode: WebViewer.Modes.SPREADSHEET_EDITOR,
123 }, viewerElement);
124
125 viewerElement.addEventListener('ready', () => {
126 this.iframeWindow = viewerElement.querySelector('iframe').contentWindow;
127 })
128
129 }
130
131 handleReceiveMessage(event) {
132 const me = this;
133 if (event.isTrusted && typeof event.data === 'object') {
134 switch (event.data.type) {
135 case 'SAVE_DOCUMENT':
136 const cvId = event.data.payload.contentDocumentId;
137 saveDocument({ json: JSON.stringify(event.data.payload), recordId: this.recordId ? this.recordId : '', cvId: cvId })
138 .then((response) => {
139 me.iframeWindow.postMessage({ type: 'DOCUMENT_SAVED', response }, '*')
140 fireEvent(this.pageRef, 'refreshOnSave', response);
141 })
142 .catch(error => {
143 me.iframeWindow.postMessage({ type: 'DOCUMENT_SAVED', error }, '*')
144 fireEvent(this.pageRef, 'refreshOnSave', error);
145 console.error(event.data.payload.contentDocumentId);
146 console.error(JSON.stringify(error));
147 this.showNotification('Error', error.body, 'error')
148 });
149 break;
150 default:
151 break;
152 }
153 }
154 }
155
156 downloadDocument() {
157 this.iframeWindow.postMessage({type: 'DOWNLOAD_DOCUMENT' }, '*')
158 }
159
160 @api
161 closeDocument() {
162 this.iframeWindow.postMessage({type: 'CLOSE_DOCUMENT' }, '*')
163 }
164}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales