Wednesday, June 26, 2019

Custom File Upload in Lightning Web Components(lwc)

This post explains how to use custom file upload in Lightning web components(lwc).

Note
This component only works for small size files, it will not work for the big size files.

Example

customFileUploader.html
<template>
    <lightning-card title="Custom File Uploader">
            <div style="margin-left:4%">
                <div>
                    <lightning-input label="" name="file uploader" onchange={handleFilesChange} type="file" multiple></lightning-input>
                </div><br/>
                <div class="slds-text-body_small slds-text-color_error">{fileName}
                <template if:true={showLoadingSpinner}>
                        <lightning-spinner alternative-text="Uploading......" size="medium"></lightning-spinner>
                    </template>
                </div><br/>
                <div>
                    <lightning-button class="slds-m-top--medium" label={UploadFile} onclick={handleSave} variant="brand" disabled={isTrue}></lightning-button>
                </div>
            </div><br/><br/>
            <!-- Datatable to show the related files of the record -->
                <lightning-card title="Related Files of the record" icon-name="standard:account">
                    <div style="width: auto;">
                        <template if:true={data}>
                                <lightning-datatable
                                        data={data}
                                        columns={columns}
                                        key-field="id"
                                        onrowselection={getSelectedRecords}>
                                </lightning-datatable>
                        </template>
                    </div>
                </lightning-card>
    
        </lightning-card>
</template>

customFileUploader.js
import { LightningElement, track, api } from 'lwc';
import saveFile from '@salesforce/apex/LWCExampleController.saveFile';
import releatedFiles from '@salesforce/apex/LWCExampleController.releatedFiles';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';

const columns = [
    {label: 'Title', fieldName: 'Title'}
];

export default class CustomFileUploader extends LightningElement {
    @api recordId;
    @track columns = columns;
    @track data;
    @track fileName = '';
    @track UploadFile = 'Upload File';
    @track showLoadingSpinner = false;
    @track isTrue = false;
    selectedRecords;
    filesUploaded = [];
    file;
    fileContents;
    fileReader;
    content;
    MAX_FILE_SIZE = 1500000;


    connectedCallback() {
        this.getRelatedFiles();
    }

    // getting file 
    handleFilesChange(event) {
        if(event.target.files.length > 0) {
            this.filesUploaded = event.target.files;
            this.fileName = event.target.files[0].name;
        }
    }

    handleSave() {
        if(this.filesUploaded.length > 0) {
            this.uploadHelper();
        }
        else {
            this.fileName = 'Please select file to upload!!';
        }
    }

    uploadHelper() {
        this.file = this.filesUploaded[0];
       if (this.file.size > this.MAX_FILE_SIZE) {
            window.console.log('File Size is to long');
            return ;
        }
        this.showLoadingSpinner = true;
        // create a FileReader object 
        this.fileReader= new FileReader();
        // set onload function of FileReader object  
        this.fileReader.onloadend = (() => {
            this.fileContents = this.fileReader.result;
            let base64 = 'base64,';
            this.content = this.fileContents.indexOf(base64) + base64.length;
            this.fileContents = this.fileContents.substring(this.content);
            
            // call the uploadProcess method 
            this.saveToFile();
        });
    
        this.fileReader.readAsDataURL(this.file);
    }

    // Calling apex class to insert the file
    saveToFile() {
        saveFile({ idParent: this.recordId, strFileName: this.file.name, base64Data: encodeURIComponent(this.fileContents)})
        .then(result => {
            window.console.log('result ====> ' +result);
            // refreshing the datatable
            this.getRelatedFiles();

            this.fileName = this.fileName + ' - Uploaded Successfully';
            this.UploadFile = 'File Uploaded Successfully';
            this.isTrue = true;
            this.showLoadingSpinner = false;

            // Showing Success message after file insert
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Success!!',
                    message: this.file.name + ' - Uploaded Successfully!!!',
                    variant: 'success',
                }),
            );

        })
        .catch(error => {
            // Showing errors if any while inserting the files
            window.console.log(error);
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Error while uploading File',
                    message: error.message,
                    variant: 'error',
                }),
            );
        });
    }
    
    // Getting releated files of the current record
    getRelatedFiles() {
        releatedFiles({idParent: this.recordId})
        .then(data => {
            this.data = data;
        })
        .catch(error => {
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Error!!',
                    message: error.message,
                    variant: 'error',
                }),
            );
        });
    }

    // Getting selected rows to perform any action
    getSelectedRecords(event) {
        let conDocIds;
        const selectedRows = event.detail.selectedRows;
        conDocIds = new Set();
        // Display that fieldName of the selected rows
        for (let i = 0; i < selectedRows.length; i++){
            conDocIds.add(selectedRows[i].ContentDocumentId);
        }

        this.selectedRecords = Array.from(conDocIds).join(',');

        window.console.log('selectedRecords =====> '+this.selectedRecords);
    }

}

customFileUploader.js.meta-xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="CustomFileUploader">
    <apiVersion>46.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

LWCExampleController.cls
public inherited sharing class LWCExampleController {
    
    @AuraEnabled
    public static ContentVersion saveFile(Id idParent, String strFileName, String base64Data) {
        // Decoding base64Data
        base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');
        
        // inserting file
        ContentVersion cv = new ContentVersion();
        cv.Title = strFileName;
        cv.PathOnClient = '/' + strFileName;
        cv.FirstPublishLocationId = idParent;
        cv.VersionData = EncodingUtil.base64Decode(base64Data);
        cv.IsMajorVersion = true;
        Insert cv;
        return cv;
    }

    @AuraEnabled
    public static list<contentversion> releatedFiles(Id idParent){
        list<id> lstConDocs = new list<id>();
        for(ContentDocumentLink cntLink : [Select Id, ContentDocumentId From ContentDocumentLink Where LinkedEntityId =:idParent]) {
            lstConDocs.add(cntLink.ContentDocumentId);
        }
        if(!lstConDocs.isEmpty()) {
            return [SELECT Id, Title, ContentDocumentId FROM ContentVersion WHERE ContentDocumentId IN :lstConDocs];
        }
        else {
            return null;
        }
     
    }
    
}

Result

23 comments:

  1. How to upload large files into LWC ?

    ReplyDelete
    Replies
    1. you can use standard salesforce tag : lightning-file-upload, it support till 2 GB of file to upload but will works with the record id where it needs to be uploaded.

      Delete
    2. lightning-file-upload Will not supporting uploading new version as it always creates the new Content Version, Content Document and Content Link and ContentDocumentId on Content version and ContentDocumentLink is not writable

      Delete
  2. Replies
    1. yes it will
      1. Allow the guest users to upload files.
      2. To use LWC in communities, please check below link.
      https://www.salesforcecodecrack.com/2019/04/how-to-use-lightning-web-componentlwc.html

      Delete
  3. How it is working I need to upload file before case creation

    ReplyDelete
  4. How to enable the import button only after the file upload here?

    ReplyDelete
  5. Does it work in public sites ? Because i have a problem with lightning file upload with lightning out !

    ReplyDelete
    Replies
    1. yes it works in public sites.

      Delete
    2. As per SF documentation "you can omit the record-id attribute when specifying file-field-name and file-field-value attributes. However, if you provide the record-id, file-field-name and file-field-value attributes, the record ID is ignored if the uploading user is a guest user."

      Delete
  6. How to clear the file before saving like cross button icon in lightning file upload

    ReplyDelete
  7. As per the code looks like 1.5 MB is the maximum limit.Can you please confirm if my understanding is correct ?

    MAX_FILE_SIZE = 1500000;

    When I tried processing 3 MB file it went through !


    Is there any documentation around the max file size which you can share ?

    ReplyDelete
    Replies
    1. which component is controlling the size of the file? except MAX_FILE_SIZE

      Delete
  8. Hi,
    Could you please help me to upload the multiple files. This example has only for one file. let me know the places where we need to change the code.

    As it is very urgent for me, could you please respond at the earliest.

    Thanks

    ReplyDelete
    Replies
    1. I Posted new article on multiple files upload in LWC, check belw link
      https://www.salesforcecodecrack.com/2020/07/custom-multiple-file-upload-in.html

      Delete
    2. Hi @Shaik Nagajani ... I want to create a form in which user make an input in the form and will upload an image while creation of the form ...After user clicks on submit the record will gets created ..but my issue here is theim not getting the uploaded file image in the related tab for the particular record

      Delete
  9. Without querying the file from Server and processing, can we access the contents of the file on upload and process on the client side itself. Because when i try to pass the file from apex controller I'm getting String length exceeds maximum exception 6000000. Please let me know your comments.

    ReplyDelete
  10. HOW CAN I DO INTEGRATION WITH EXTERNAL SYSTEM USING THIS COMMPONENT

    ReplyDelete

  11. Can we use this component in external community

    ReplyDelete
  12. Can this component work on partner community

    ReplyDelete
  13. How do we clear the value of file after the file has been uploaded?

    ReplyDelete
  14. I want to re-upload the same file after i change something in side file but the event handleFilesChange not working without refresh the page.

    ReplyDelete
  15. Hi
    How can i change the text Upload files or drop files to Attach file in this
    thanks in adv

    ReplyDelete