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.

Get the answers you need: Chat with us