Files Upload and Preview using Lightning Aura

In Salesforce, files refer to any type of document or digital asset that can be stored, shared, and
collaborated on within the platform. By leveraging Salesforce’s file management system capabilities,
organizations can improve collaboration and enhance productivity and ensure security of their data.

In this post we are going to implement requirement of uploading multiple files using lightning aura component as well as preview uploaded document. Below are some objects which are associated with storing the document.

Objects

  1. ContentDocument : It represents a document that has been uploaded on salesforce platform. Some important fields are FileExtension determines extension of file and FileType determine by FileExtension, Title stores tile of document, ContentSize size of documents in bytes.
  2. ContentDocumentLink : Record of ContentDocumentLink represent link between ContentDocument and another object in salesforce. For example if file is related to Account record then there will be contentDocumentLink record connecting ContentDocument to Account. Some important fields are ContentDocumentId is related to ContentDocument object through lookup relationship contains Id of document. LinkedEntityId is a lookup relationship contains Id of related or linked object. ShareType is the permission granted to the user of the shared file in a library. V: (Viewer) User can explicitly view but cannot edit file. C: (Collaborator) User can view and edit shared files. I: (Inferred) determine by the related record.
  3. ContentVersion : This object represents specific version of file that has been edited or uploaded on salesforce. Multiple ContentVersion records can be linked with same contentDocument record.

Source Code

Apex

public class FileUploadController {
	@AuraEnabled
    public static String fileUpload (String parentId, String name, String fileType, String fileData){
        try{
            System.debug('**fileData** '+EncodingUtil.base64Decode(fileData));
            ContentVersion fileVersion = new ContentVersion();
            fileVersion.Title = name;
            fileVersion.PathOnClient = name;
            fileVersion.VersionData = EncodingUtil.base64Decode(fileData);
            insert fileVersion;
            System.debug('**fileVersion** '+fileVersion);
            
            ContentDocumentLink newLink = new ContentDocumentLink();
            newLink.LinkedEntityId = parentId;
            newLink.ShareType = 'V';
            newLink.ContentDocumentId = [SELECT Id,ContentDocumentId FROM ContentVersion WHERE Id=:fileVersion.Id].ContentDocumentId;
            insert newLink;
            
            return String.valueOf(newLink.ContentDocumentId);
        }
        catch(Exception ex){
            System.debug('Exception occured on line No. '+ex.getLineNumber() +'Error Message '+ex.getMessage());
            throw new AuraHandledException('Exception: ' + ex.getMessage() + 'on Line Number: '+ex.getLineNumber());
        }
    }
}

Lightning Component

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" controller="FileUploadController">
    <aura:attribute name="recordId" type="string"/> 
    <aura:attribute name="contentDocIds" type="List" access="global"/>
    <aura:attribute name="fileName" type="List" access="global"/>
    <lightning:spinner aura:id="mySpinner" title="Uploading..." varient="brand" class="slds-hide"/>
    <div class="slds-grid slds-gutters">
        <div class="slds-col">
            <lightning:input type="file" 
                             aura:id="fileUpload"
                             label="File Upload" 
                             name="file" 
                             multiple="true" 
                             onchange="{!c.filesChangeHandler}"/>
            <aura:if isTrue="{!v.fileName.length > 0}">
                <aura:iteration items="{!v.fileName}" var="val">
                    <div class="slds-text-color_success">
                        {!val}<br/>
                    </div>
                </aura:iteration>
                <aura:set attribute="else">
                    <div class="slds-text-color_error">
                        No Files Selected...
                    </div>
                </aura:set>
            </aura:if>
            <lightning:button name="Upload File" label="Upload File" variant="brand" onclick="{!c.uploadFiles}"/>
        </div>
    </div>
    <br/>
    <div class="slds-grid slds-gutters">
        <aura:if isTrue="{!v.contentDocIds.length > 0}">
            <aura:iteration items="{!v.contentDocIds}" var="val">
                <div class="slds-col">
                    <lightning:fileCard fileId="{!val}"/>
                </div>
            </aura:iteration>
        </aura:if>
    </div>
</aura:component>

Controller

({
    filesChangeHandler: function(component, event, helper){
        var files = component.find("fileUpload").get("v.files");
        var fileName = [];
        Array.from(files).forEach((file,index) => {
            fileName.push(file.name);
        });
        component.set("v.fileName",fileName);
    },
     uploadFiles: function(component, event, helper){
        $A.util.removeClass(component.find("mySpinner"),"slds-hide"); 
        var files = component.find("fileUpload").get("v.files");
         if(!$A.util.isEmpty(files) && !$A.util.isUndefinedOrNull(files)){
             if(files.length > 0){
                 helper.uploadFiles(component, event, helper, files);
             }
             else{
                 $A.util.addClass(component.find("mySpinner"),"slds-hide"); 
             	 helper.showToast(component, 'error', 'Please Select File to Upload')
             }
         }
         else{
             $A.util.addClass(component.find("mySpinner"),"slds-hide"); 
             helper.showToast(component, 'error', 'Please Select File to Upload');         
         }
     },        
})

Helper

({
    uploadFiles: function(component, event, helper, files){
        var self = this;
        Array.from(files).forEach((file,index) => {
            var readFile = new FileReader();
            readFile.onload = $A.getCallback(function() {
            	var fileData = readFile.result;
            	fileData = fileData.substring(fileData.indexOf('base64,') + 'base64,'.length)
            	self.insertDocuments(component, event, helper, fileData, file);
        	});
            readFile.readAsDataURL(file);
        });
    },
 	insertDocuments: function(component, event, helper, fileData, file){
    	$A.util.removeClass(component.find("mySpinner"),"slds-hide");
    	var parentId = component.get("v.recordId");
    	var size = file.size;
    	var fileName = file.name;
    	var fileType = file.type; 
    	var action  = component.get("c.fileUpload");
    	action.setParams({
            'parentId': parentId,
            'name': fileName,
            'fileType': fileType,
            'fileData': fileData
    	});
    	action.setCallback(this, function(response){
        	var state = response.getState();
            $A.util.addClass(component.find("mySpinner"),"slds-hide");
            if(state === 'SUCCESS'){
                var result = response.getReturnValue();
                if(!$A.util.isEmpty(result) && !$A.util.isUndefinedOrNull(result)){
                    var contentDocIds = component.get("v.contentDocIds");
                    contentDocIds.push(result);
                    component.set("v.contentDocIds",contentDocIds);
                    var emptyFiles = [];
                    component.find("fileUpload").set("v.files",null);
                    component.set("v.fileName",emptyFiles);
                    this.showToast(component, 'success','Document Inserted Successfully');
                }
                else{
                    this.showToast(component, 'error','Something went wrong, Not able to fetch ContentDocumentId');
                }
            }
            else{
                var errors = response.getError();
                if(errors){
                    this.showToast(component, 'error','Exception occured');
                }
            }
    	});
    	$A.enqueueAction(action);
	},
    showToast: function(cmp, type, message){
        var notification = $A.get("e.force:showToast");
        notification.setParams({
            message: message,
            duration: '1000',
            type: type,
            mode: 'pester'
        });
        notification.fire();
    }
})

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *