Some test text!

Search
Hamburger Icon

Salesforce / Guides / Saving Annotations

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:

async function saveDocument() {
  const doc = docViewer.getDocument();
  if (!doc) {
    return;
  }
  instance.openElement('loadingModal');

  const fileType = doc.getType();
  const filename = doc.getFilename();
  const xfdfString = await docViewer.getAnnotationManager().exportAnnotations();
  const data = await doc.getFileData({
    // Saves the document with annotations in it
    xfdfString
  });

  let binary = '';
  const bytes = new Uint8Array(data);
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }

  const base64Data = window.btoa(binary);

  const payload = {
    title: filename.replace(/\.[^/.]+$/, ""),
    filename,
    base64Data,
    contentDocumentId: doc.__contentDocumentId
  }
  // Post message to LWC
  parent.postMessage({ type: 'SAVE_DOCUMENT', payload }, '*');
}
async function saveDocument() {
  const doc = docViewer.getDocument();
  if (!doc) {
    return;
  }
  readerControl.openElement('loadingModal');

  const fileType = doc.getType();
  const filename = doc.getFilename();
  const xfdfString = await docViewer.getAnnotationManager().exportAnnotations();
  const data = await doc.getFileData({
    // Saves the document with annotations in it
    xfdfString
  });

  let binary = '';
  const bytes = new Uint8Array(data);
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }

  const base64Data = window.btoa(binary);

  const payload = {
    title: filename.replace(/\.[^/.]+$/, ""),
    filename,
    base64Data,
    contentDocumentId: doc.__contentDocumentId
  }
  // Post message to LWC
  parent.postMessage({ type: 'SAVE_DOCUMENT', payload }, '*');
}

Passing blob data to Apex

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

//snipped for brevity
//see full github sample to see how to set up event flow
handleReceiveMessage(event) {
  const me = this;
  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      case 'SAVE_DOCUMENT':
        saveDocument({ json: JSON.stringify(event.data.payload), recordId: this.recordId }).then((response) => {
          me.iframeWindow.postMessage({ type: 'DOCUMENT_SAVED', response }, '*')
        }).catch(error => {
          console.error(JSON.stringify(error));
        });
        break;
      default:
        break;
    }
  }
}

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.

// force-app\main\default\classes\ContentVersionController.cls
public with sharing class ContentVersionController {
// snipped for brevity
  @AuraEnabled
  public static void saveDocument(String json, String recordId) {
    try {
      PDFTron_ContentVersionPayload pl = PDFTron_ContentVersionPayload.parse(json);
      ContentVersion cv = new ContentVersion();
      cv.ContentLocation = 'S'; //File originated in Salesforce
      if(pl.contentDocumentId != null) {
        cv.ContentDocumentId = pl.contentDocumentId;
        cv.ReasonForChange = 'Saved from WebViewer';//only for file updates
      } else {
        for(ContentDocumentLink cdl : 
          [   SELECT ContentDocumentId, ContentDocument.Title
              FROM ContentDocumentLink 
              WHERE LinkedEntityId = :recordId
              AND ContentDocument.Title = :pl.title ]) {
                
                if(cdl.ContentDocumentId != null) {
                  cv.ContentDocumentId = cdl.ContentDocumentId;
                }
        }
      }
      cv.VersionData = EncodingUtil.base64Decode(pl.base64Data);
      cv.Title = pl.title;
      cv.PathOnClient = pl.filename;
            
      insert cv; 
    } catch (Exception e) {
      throw new AuraHandledException(e.getMessage());
    }
  }
}

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

Trial setup questions? Ask experts on Discord
Need other help? Contact Support
Pricing or product questions? Contact Sales