Convert to PDF using Visualforce Page in Lightning Web Component Salesforce | LWC Stack ☁️⚡️

 In this blog you will learn how you can convert to PDF using Visualforce page in Lightning Web Component. 

If you are following my blogs then you must be aware that we have a similar functionality with PDF JS library and using that we have converted the content to PDF

This time we will do it using a Visualforce page. In VF page we have option to render it as a PDF but for LWC if you will try to do it by embedding the component then it's not going to work as the VF will generate the PDF before loading the LWC component.

Another workaround for that is to send formatted data to VF page and then render it as PDF.

In this example I will convert an Image to PDF and save it as File using Visualforce Page and LWC.


So in this blog you will learn following key things : 

✅ Send data from your LWC to Visualforce Page

✅ Load it as a PDF

✅ Save the PDF as a file in your Salesforce Org


PreviewFileThumbnails HTML (Parent component to display file thumbnails)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
  <lightning-file-upload
    name="fileUploader"
    accept={acceptedFormats}
    record-id={recordId}
    onuploadfinished={handleUploadFinished}
    multiple
  >
  </lightning-file-upload>

  <br />
  <div
    class="
      slds-page-header__row
      slds-var-m-top_x-small
      slds-var-m-left_medium
      slds-grid slds-wrap
    "
  >
    <ul class="slds-grid slds-wrap slds-gutters">
      <template if:true={loaded}>
        <template for:each={files} for:item="file">
          <c-preview-file-thumbnail-card
            key={file.Id}
            file={file}
            record-id={recordId}
            thumbnail={file.thumbnailFileCard}
            onrefreshlist={handleRefresh}
          ></c-preview-file-thumbnail-card>
        </template>
      </template>
    </ul>
  </div>
</template>


PreviewFileThumbnails JS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { LightningElement, wire, api, track } from "lwc";
import { refreshApex } from "@salesforce/apex";
import { ShowToastEvent } from "lightning/platformShowToastEvent";
import getFileVersions from "@salesforce/apex/AccountController.getVersionFiles";

export default class PreviewFileThumbnails extends LightningElement {
  loaded = false;
  @track fileList;
  @api recordId;
  @track files = [];
  get acceptedFormats() {
    return [".pdf", ".png", ".jpg", ".jpeg"];
  }

  @wire(getFileVersions, { recordId: "$recordId" })
  fileResponse(value) {
    this.wiredActivities = value;
    const { data, error } = value;
    this.fileList = "";
    this.files = [];
    if (data) {
      this.fileList = data;
      for (let i = 0; i < this.fileList.length; i++) {
        let file = {
          Id: this.fileList[i].Id,
          Title: this.fileList[i].Title,
          Extension: this.fileList[i].FileExtension,
          ContentDocumentId: this.fileList[i].ContentDocumentId,
          ContentDocument: this.fileList[i].ContentDocument,
          CreatedDate: this.fileList[i].CreatedDate,
          thumbnailFileCard:
            "/sfc/servlet.shepherd/version/renditionDownload?rendition=THUMB120BY90&versionId=" +
            this.fileList[i].Id +
            "&operationContext=CHATTER&contentId=" +
            this.fileList[i].ContentDocumentId,
          downloadUrl:
            "/sfc/servlet.shepherd/document/download/" +
            this.fileList[i].ContentDocumentId
        };
        this.files.push(file);
      }
      this.loaded = true;
    } else if (error) {
      this.dispatchEvent(
        new ShowToastEvent({
          title: "Error loading Files",
          message: error.body.message,
          variant: "error"
        })
      );
    }
  }
  handleUploadFinished(event) {
    const uploadedFiles = event.detail.files;
    refreshApex(this.wiredActivities);
    this.dispatchEvent(
      new ShowToastEvent({
        title: "Success!",
        message: uploadedFiles.length + " Files Uploaded Successfully.",
        variant: "success"
      })
    );
  }
  handleRefresh(event) {
    refreshApex(this.wiredActivities);
  }
}


PreviewFileThumbnailCard HTML (Child component to display thumbnails)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
  <template if:true={loading}>
    <lightning-spinner alternative-text="Loading"></lightning-spinner>
  </template>
  <template if:true={file}>
    <c-preview-file-modal
      url={file.downloadUrl}
      file-extension={file.Extension}
    ></c-preview-file-modal>
    <li
      class="
        slds-col
        slds-var-p-vertical_x-small
        slds-small-size_1-of-2
        slds-medium-size_1-of-4
        slds-large-size_1-of-6
      "
    >
      <div class="slds-file slds-file_card slds-has-title" style="width: 14rem">
        <figure>
          <a
            onclick={filePreview}
            class="slds-file__crop slds-file__crop_4-by-3 slds-m-top_x-small"
          >
            <img src={thumbnail} alt={file.title} />
          </a>
          <figcaption class="slds-file__title slds-file__title_card">
            <div class="slds-media slds-media_small slds-media_center">
              <lightning-icon
                icon-name={iconName}
                alternative-text={file.Title}
                title={file.Title}
                size="xx-small"
              >
                <span class="slds-assistive-text"
                  >{file.Title}.{file.Extension}</span
                >
              </lightning-icon>
              <div class="slds-media__body slds-var-p-left_xx-small">
                <span class="slds-file__text slds-truncate" title={file.Title}
                  >{file.Title}.{file.Extension}</span
                >
              </div>
            </div>
          </figcaption>
        </figure>

        <div class="slds-is-absolute menuOptions">
          <lightning-button-menu
            alternative-text="Show File Menu"
            variant="border-filled"
            onselect={handleOnselect}
            icon-size="xx-small"
          >
            <lightning-menu-item
              value="preview"
              label="Preview"
            ></lightning-menu-item>
            <lightning-menu-item
              value="delete"
              label="Delete"
            ></lightning-menu-item>
            <template if:true={showConvertButton}>
              <lightning-menu-item
                value="convert"
                label="Convert to PDF"
              ></lightning-menu-item>
            </template>
          </lightning-button-menu>
        </div>
      </div>
    </li>
  </template>
</template>


PreviewFileThumbnailCard JS

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
import { LightningElement, api } from "lwc";
import convertToPdf from "@salesforce/apex/AccountController.convertToPdf";

export default class PreviewFileThumbnailCard extends LightningElement {
  @api file;
  @api recordId;
  @api thumbnail;

  loading = false;
  showConvertButton = false;

  get iconName() {
    if (this.file.Extension) {
      if (this.file.Extension === "pdf") {
        return "doctype:pdf";
      }
      if (this.file.Extension === "ppt") {
        return "doctype:ppt";
      }
      if (this.file.Extension === "xls") {
        return "doctype:excel";
      }
      if (this.file.Extension === "csv") {
        return "doctype:csv";
      }
      if (this.file.Extension === "txt") {
        return "doctype:txt";
      }
      if (this.file.Extension === "xml") {
        return "doctype:xml";
      }
      if (this.file.Extension === "doc") {
        return "doctype:word";
      }
      if (this.file.Extension === "zip") {
        return "doctype:zip";
      }
      if (this.file.Extension === "rtf") {
        return "doctype:rtf";
      }
      if (this.file.Extension === "psd") {
        return "doctype:psd";
      }
      if (this.file.Extension === "html") {
        return "doctype:html";
      }
      if (this.file.Extension === "gdoc") {
        return "doctype:gdoc";
      }
    }
    this.showConvertButton = true;
    return "doctype:image";
  }

  filePreview() {
    console.log("###Click");
    const showPreview = this.template.querySelector("c-preview-file-modal");
    showPreview.show();
  }
  handleOnselect(event) {
    let selection = event.detail.value;
    console.log("###handle on select : " + selection);

    if (selection === "preview") {
      this.filePreview();
    } else if (selection === "delete") {
      //code to delete the file
    } else if (selection === "convert") {
      console.log("###File : " + JSON.stringify(this.file));
      this.loading = true;
      let cv = {
        Id: this.file.Id,
        Title: this.file.Title,
        ContentDocumentId: this.file.ContentDocumentId,
        ContentLocation: "S"
      };
      convertToPdf({ cv: cv })
        .then(() => {
          this.error = undefined;

          setTimeout(() => {
            const selectedEvent = new CustomEvent("refreshlist");
            this.dispatchEvent(selectedEvent);
            this.loading = false;
          }, 5000);
        })
        .catch((error) => {
          this.loading = false;
          this.error = error;
          this.dispatchEvent(
            new ShowToastEvent({
              title: "Error while converting file",
              message: error.message,
              variant: "error"
            })
          );
        });
    }
  }
}


PreviewFileThumbnailCard.css

1
2
3
4
5
.menuOptions {
  top: 3px;
  right: 5px;
  z-index: 10;
}


PDFConverter (Visualforce Page to Convert the Data)

1
2
3
4
5
<apex:page Controller="AccountController" applyBodyTag="false" renderAs="pdf" standardStylesheets="false" applyHtmlTag="false" showHeader="false" action="{!init}">
    <div style="width:100%;">
        <img src="/sfc/servlet.shepherd/version/download/{!contentVersionId}" style="position: absolute; top: 0;" width="100%"/>
    </div>
</apex:page>


ConverttoPDF Queueable class

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public with sharing class ConverttoPDF implements Queueable, Database.AllowsCallouts {
    private List<ContentVersion> contentVersions = new List<ContentVersion>();

	public ConverttoPDF(List<ContentVersion> contentVersions) {
		this.contentVersions = contentVersions;
	}
	public void execute(QueueableContext context) {
		if (this.contentVersions.size() == 0) {
			return;
		}
		List<ContentVersion> contentVersionToInsert = new List<ContentVersion>();
		for (ContentVersion contentVersion : contentVersions) {
			PageReference pdfFile = new PageReference('/apex/PDFConverter?cvId=' + contentVersion.Id);

            if (pdfFile == null) {
				continue;
			}

			Blob body;
			try {
			    body = pdfFile.getContentAsPDF();
			} catch (VisualforceException e) {
				System.debug('Failed to convert to pdf file.' + e.getMessage());
			}
            
			ContentVersion newContentVersion = new ContentVersion();
			newContentVersion.VersionData = body;
			newContentVersion.Title = contentVersion.Title;
			newContentVersion.PathOnClient = contentVersion.Title + '.pdf';
			newContentVersion.ContentDocumentId = contentVersion.ContentDocumentId;
			newContentVersion.ContentLocation = contentVersion.ContentLocation;
			newContentVersion.IsMajorVersion = false;
			contentVersionToInsert.add(newContentVersion);
		}

		if (contentVersionToInsert.size() > 0) {
			insert contentVersionToInsert;
			
		}
	}
}


Account Controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public with sharing class AccountController{
   	public String contentVersionId { get; set; }

    @AuraEnabled(cacheable=true)
    public static List<ContentVersion> getVersionFiles(String recordId){
        try {
            List<ContentDocumentLink> contentDocumentLinks=[
                                                            SELECT
                                                                Id,
                                                                LinkedEntityId,
                                                                ContentDocumentId,
                                                                ContentDocument.LatestPublishedVersionId,
                                                                ContentDocument.LatestPublishedVersion.Title
                                                            FROM ContentDocumentLink
                                                            WHERE LinkedEntityId=:recordId];

            Set<Id> documentIds = new Set<Id>();
            for (ContentDocumentLink cdl : contentDocumentLinks) {
                documentIds.add(cdl.ContentDocumentId);
            }

            return [
                    SELECT
                        Id,
                        Title,
                        ContentDocumentId,
                        FileType, 
                        ContentSize,
                        FileExtension,
                        VersionNumber,
                        CreatedDate,
                        VersionData,
                        FirstPublishLocationId
                    FROM ContentVersion
                    WHERE ContentDocumentId IN :documentIds AND IsLatest = TRUE
			        ORDER BY ContentDocument.CreatedDate DESC
		];
        
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
    }
    
    @AuraEnabled
    public static String convertToPdf(ContentVersion cv) {
		return System.enqueueJob(new ConverttoPDF(new List<ContentVersion>{ cv }));
		
	}

    public PageReference init() {
		this.contentVersionId = String.escapeSingleQuotes(ApexPages.currentPage().getParameters().get('cvId')).trim();
        return null;
    }

}


Output



Checkout complete video tutorial below


 If you have any question please leave a comment below.

If you would like to add something to this post please leave a comment below.
Share this blog with your friends if you find it helpful somehow !

Thanks
Happy Coding :)

Post a Comment

0 Comments