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

15 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. 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
  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
  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