Section:

Saving Annotations Stored in Salesforce

Saving Annotations in Salesforce

Adding a new ContentVersion record from WebViewer LWC

First, you need to generate a base64 string that is sent to the Apex backend. Use the following function in your config_apex.js file to achieve this:

JavaScript (v8.0+)

1async function saveDocument() {
2 const doc = docViewer.getDocument();
3 if (!doc) {
4 return;
5 }
6 instance.openElement('loadingModal');
7
8 const fileType = doc.getType();
9 const filename = doc.getFilename();
10 const xfdfString = await docViewer.getAnnotationManager().exportAnnotations();
11 const data = await doc.getFileData({
12 // Saves the document with annotations in it
13 xfdfString
14 });
15
16 let binary = '';
17 const bytes = new Uint8Array(data);
18 for (let i = 0; i < bytes.byteLength; i++) {
19 binary += String.fromCharCode(bytes[i]);
20 }
21
22 const base64Data = window.btoa(binary);
23
24 const payload = {
25 title: filename.replace(/\.[^/.]+$/, ""),
26 filename,
27 base64Data,
28 contentDocumentId: doc.__contentDocumentId
29 }
30 // Post message to LWC
31 parent.postMessage({ type: 'SAVE_DOCUMENT', payload }, '*');
32}

JavaScript (v7.0+)

1async function saveDocument() {
2 const doc = docViewer.getDocument();
3 if (!doc) {
4 return;
5 }
6 readerControl.openElement('loadingModal');
7
8 const fileType = doc.getType();
9 const filename = doc.getFilename();
10 const xfdfString = await docViewer.getAnnotationManager().exportAnnotations();
11 const data = await doc.getFileData({
12 // Saves the document with annotations in it
13 xfdfString
14 });
15
16 let binary = '';
17 const bytes = new Uint8Array(data);
18 for (let i = 0; i < bytes.byteLength; i++) {
19 binary += String.fromCharCode(bytes[i]);
20 }
21
22 const base64Data = window.btoa(binary);
23
24 const payload = {
25 title: filename.replace(/\.[^/.]+$/, ""),
26 filename,
27 base64Data,
28 contentDocumentId: doc.__contentDocumentId
29 }
30 // Post message to LWC
31 parent.postMessage({ type: 'SAVE_DOCUMENT', payload }, '*');
32}

Passing blob data to Apex

Once you have your document's data converted, you can pass it to Apex. This snippet uses

JavaScript

1//snipped for brevity
2//see full github sample to see how to set up event flow
3handleReceiveMessage(event) {
4 const me = this;
5 if (event.isTrusted && typeof event.data === 'object') {
6 switch (event.data.type) {
7 case 'SAVE_DOCUMENT':
8 saveDocument({ json: JSON.stringify(event.data.payload), recordId: this.recordId }).then((response) => {
9 me.iframeWindow.postMessage({ type: 'DOCUMENT_SAVED', response }, '*')
10 }).catch(error => {
11 console.error(JSON.stringify(error));
12 });
13 break;
14 default:
15 break;
16 }
17 }
18}

Creating a new ContentVersion record from blob data

Finally, you can use the below Apex code snippet to create a new ContentVersion record. This sample also links the newly created document to the sObject record you started from.

Apex

1// force-app\main\default\classes\ContentVersionController.cls
2public with sharing class ContentVersionController {
3// snipped for brevity
4 @AuraEnabled
5 public static void saveDocument(String json, String recordId) {
6 try {
7 PDFTron_ContentVersionPayload pl = PDFTron_ContentVersionPayload.parse(json);
8 ContentVersion cv = new ContentVersion();
9 cv.ContentLocation = 'S'; //File originated in Salesforce
10 if(pl.contentDocumentId != null) {
11 cv.ContentDocumentId = pl.contentDocumentId;
12 cv.ReasonForChange = 'Saved from WebViewer';//only for file updates
13 } else {
14 for(ContentDocumentLink cdl :
15 [ SELECT ContentDocumentId, ContentDocument.Title
16 FROM ContentDocumentLink
17 WHERE LinkedEntityId = :recordId
18 AND ContentDocument.Title = :pl.title ]) {
19
20 if(cdl.ContentDocumentId != null) {
21 cv.ContentDocumentId = cdl.ContentDocumentId;
22 }
23 }
24 }
25 cv.VersionData = EncodingUtil.base64Decode(pl.base64Data);
26 cv.Title = pl.title;
27 cv.PathOnClient = pl.filename;
28
29 insert cv;
30 } catch (Exception e) {
31 throw new AuraHandledException(e.getMessage());
32 }
33 }
34}

You can also find the full source code for an end to end flow in this Github repository.

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales