Showing posts with label Custom File upload. Show all posts
Showing posts with label Custom File upload. Show all posts

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

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