Sunday, July 5, 2020

Custom Multiple File Upload in Lightning Web Component(lwc)

This post explains how to use custom multiple 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.

customMulitipleFileUploader.html
<template>
    <lightning-card title="Custom Multiple File Uploader In LWC">
        <div style="margin-left:4%">
            <div>
                <lightning-input type="file" 
                                 label="" 
                                 onchange={handleFileChanges} 
                                 multiple>
                </lightning-input>
            </div>
            
            <div if:true={fileNames} class="slds-text-body_small slds-text-color_error">{fileNames}
                <template if:true={showLoadingSpinner}>
                    <lightning-spinner alternative-text="Uploading......" size="medium"></lightning-spinner>
                </template>
            </div><br />

            <lightning-button class="slds-m-top--medium" 
                              label="Upload Files" 
                              onclick={handleSaveFiles} 
                              variant="brand">
            </lightning-button>
        </div><br />
        <template if:true={data}>
            <lightning-card title="Uploaded Files" icon-name="standard:account">
                <div style="width: auto;">
                    <lightning-datatable data={data} 
                                         columns={columns} 
                                         key-field="id">
                    </lightning-datatable>
                </div>
            </lightning-card>
        </template>
    </lightning-card>
</template>
customMulitipleFileUploader.js
import {LightningElement, track} from 'lwc';
import saveFiles from '@salesforce/apex/GenericController.saveFiles';
import getFiles from '@salesforce/apex/GenericController.returnFiles';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';

const columns = [{
    label: 'Title',
    fieldName: 'FileName',
    type: 'url',
    typeAttributes: {
        label: {
            fieldName: 'Title'
        },
        target: '_blank'
    }
}];

export default class CustomMulitipleFileUploader extends LightningElement {
    showLoadingSpinner = false;
    @track fileNames = '';
    @track filesUploaded = [];
    @track data;
    @track columns = columns;

    handleFileChanges(event) {
        let files = event.target.files;

        if (files.length > 0) {
            let filesName = '';

            for (let i = 0; i < files.length; i++) {
                let file = files[i];

                filesName = filesName + file.name + ',';

                let freader = new FileReader();
                freader.onload = f => {
                    let base64 = 'base64,';
                    let content = freader.result.indexOf(base64) + base64.length;
                    let fileContents = freader.result.substring(content);
                    this.filesUploaded.push({
                        Title: file.name,
                        VersionData: fileContents
                    });
                };
                freader.readAsDataURL(file);
            }

            this.fileNames = filesName.slice(0, -1);
        }
    }

    handleSaveFiles() {
        this.showLoadingSpinner = true;
        saveFiles({filesToInsert: this.filesUploaded})
        .then(data => {
            this.showLoadingSpinner = false;
            const showSuccess = new ShowToastEvent({
                title: 'Success!!',
                message: this.fileNames + ' files uploaded successfully.',
                variant: 'Success',
            });
            this.dispatchEvent(showSuccess);
            this.getFilesData(data);
            this.fileNames = undefined;
        })
        .catch(error => {
            const showError = new ShowToastEvent({
                title: 'Error!!',
                message: 'An Error occur while uploading the file.',
                variant: 'error',
            });
            this.dispatchEvent(showError);
        });
    }

    getFilesData(lstIds) {
        getFiles({lstFileIds: lstIds})
        .then(data => {
            data.forEach((record) => {
                record.FileName = '/' + record.Id;
            });

            this.data = data;
        })
        .catch(error => {
            window.console.log('error ====> ' + error);
        })
    }
}
customMulitipleFileUploader.js.meta-xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>
Apex Class
public inherited sharing class GenericController {
	@AuraEnabled
    public static list<ContentVersion> returnFiles(list<String> lstFileIds){
        return [SELECT Id, Title FROM ContentVersion WHERE Id IN :lstFileIds];
    }

    @AuraEnabled
    public static list<Id> saveFiles(list<Object> filesToInsert){
        
        list<Id> lstCntVerIds = new list<Id>();
        List<ContentVersion> lstVersionsToInsert = new List<ContentVersion>();
        for (Object file : filesToInsert) {
            FileInfo fileData = (FileInfo)JSON.deserialize(JSON.serialize(file), FileInfo.class);
            ContentVersion objCntVersion = new ContentVersion();
            objCntVersion.PathOnClient = fileData.Title;
            objCntVersion.Title = fileData.Title;
            objCntVersion.VersionData = fileData.VersionData;
            lstVersionsToInsert.add(objCntVersion);
        }

        list<Database.saveResult> res = Database.insert(lstVersionsToInsert);
        for (Database.SaveResult saveResult : res) {
            if(saveResult.isSuccess()) {
                lstCntVerIds.add(saveResult.getId());
            }
        }
        return lstCntVerIds;
    }


    public class FileInfo {
        public String Title;
        public Blob VersionData;
    }
}
Output

3 comments:

  1. Apex says FileInfo is an invalid type

    ReplyDelete
  2. i need to upload large file using multiple upload ? can u please reply on this

    ReplyDelete
  3. Could you share the test class? or how I can create a file from apex?

    ReplyDelete