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
-
ContentDocument: It represents a document that has been uploaded on salesforce platform. Some important fields areFileExtensiondetermines extension of file andFileTypedetermine byFileExtension,Titlestores tile of document,ContentSizesize of documents in bytes. ContentDocumentLink: Record ofContentDocumentLinkrepresent link betweenContentDocumentand another object in salesforce. For example if file is related to Account record then there will becontentDocumentLinkrecord connectingContentDocumenttoAccount. Some important fields areContentDocumentIdis related toContentDocumentobject through lookup relationship contains Id of document.LinkedEntityIdis a lookup relationship contains Id of related or linked object.ShareTypeis 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.ContentVersion: This object represents specific version of file that has been edited or uploaded on salesforce. MultipleContentVersionrecords can be linked with samecontentDocumentrecord.
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();
}
})