In this blog I will share the code to preview files in a Modal in Lightning Web Component.
There are three component in this example -
1. PreviewFileThumbnails - The parent component to upload the file.
2. PreviewFileThumbnailCard - Child component to display image preview in a thumbnail gallery view.
3. PreviewFileModal - Child component to display selected thumbnail file in a new modal popup for preview.
Make sure to change below PDF setting in Salesforce org to see the preview in browser otherwise it will download the file instead of preview :
Go to Setup --> Security --> File Upload and Download Security
Hit edit and update the .pdf file settings to "Execute in Browser" as shown in the image below :
You may follow the code below now.
PreviewFileThumbnails.html
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 | <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} ></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 | import { LightningElement, wire, api, track } from "lwc"; import { refreshApex } from "@salesforce/apex"; import { ShowToastEvent } from "lightning/platformShowToastEvent"; import getFileVersions from "@salesforce/apex/FileController.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=THUMB720BY480&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" }) ); } } |
PreviewFileThumbnailCard.html
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 | <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" onclick={filePreview} > <figure> <a class="slds-file__crop slds-file__crop_4-by-3 slds-m-top_x-small"> <img src={thumbnail} alt={file.title} onclick={filePreview} /> </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" style="top: 3px; right: 5px; z-index: 10"> <lightning-button-menu alternative-text="Show File Menu" variant="border-filled" icon-size="xx-small" > <lightning-menu-item value="preview" label="Preview" ></lightning-menu-item> <lightning-menu-item value="delete" label="Delete" ></lightning-menu-item> </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 | import { LightningElement, api } from "lwc"; export default class PreviewFileThumbnailCard extends LightningElement { @api file; @api recordId; @api thumbnail; 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"; } } return "doctype:image"; } filePreview() { console.log("###Click"); const showPreview = this.template.querySelector("c-preview-file-modal"); showPreview.show(); } } |
PreviewFileModal.html
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 | <template> <template if:true={showModal}> <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open" > <div class="slds-modal__container"> <!-- Header Start --> <header class="slds-modal__header"> <lightning-button-icon class="slds-modal__close" title="Close" icon-name="utility:close" icon-class="slds-button_icon-inverse" onclick={closeModal} ></lightning-button-icon> <h2 id="id-of-modalheader-h2" class="slds-text-heading_large"> File Preview </h2> </header> <!-- Header End --> <div class="slds-modal__content" id="modal-content-id-1"> <lightning-layout> <lightning-layout-item flexibility="auto"> <article class="slds-card"> <div class="slds-card__body slds-card__body_inner" style="margin: 0" > <template if:false={showFrame}> <img src={url} /> </template> <template if:true={showFrame}> <iframe src={url} style="width: 100%; height: 800px" ></iframe> </template> </div> </article> </lightning-layout-item> </lightning-layout> </div> <footer class="slds-modal__footer slds-grid slds-grid_align-spread"> <lightning-button variant="brand-outline" label="Cancel" onclick={closeModal} title="Cancel" class="slds-var-m-left_x-small" ></lightning-button> </footer> </div> </section> <div class="slds-backdrop slds-backdrop_open"></div> </template> </template> |
PreviewFileModal.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import { LightningElement, api } from "lwc"; export default class PreviewFileModal extends LightningElement { @api url; @api fileExtension; showFrame = false; showModal = false; @api show() { console.log("###showFrame : " + this.fileExtension); if (this.fileExtension === "pdf") this.showFrame = true; else this.showFrame = false; this.showModal = true; } closeModal() { this.showModal = false; } } |
PreviewFileModal.css
1 2 3 4 | .slds-modal__container { width: 90% !important; max-width: 90% !important; } |
FileController.cls
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 | public with sharing class FileController{ @AuraEnabled(cacheable=true) public static List<ContentVersion> getVersionFiles(String recordId){ try { return [ SELECT Id, Title, ContentDocumentId, FileType, ContentSize, FileExtension, VersionNumber, CreatedDate, VersionData, FirstPublishLocationId FROM ContentVersion WHERE FirstPublishLocationId =:recordId ORDER BY CreatedDate DESC ]; } catch (Exception e) { throw new AuraHandledException(e.getMessage()); } } } |
Output
Checkout the complete tutorial below
3 Comments
Added data-id = contentDocumentId on the div as an attribute
ReplyDelete"div class="slds-file slds-file_card slds-has-title" style="width: 14rem" data-id={file.ContentDocumentId}
onclick={previewHandler}>
"
, but when fetching it in the onclick function as e.target.dataset.id its coming as undefined, even though i can see the value is populated correctly in html.
console.log(event.target.dataset.id)
undefined.
Any idea why ?
Got it to work. Used event.currentTarget.dataset.id instead event.target.dataset.id
DeleteAwesome, thanks for sharing it here !
Delete