
Custom File Upload In Salesforce Lightning Component – Upload Large Attachments
Hey Guys,
Today in this post we are going to learn about how to create a custom file upload salesforce lightning component. This post inspire and new updated version of ‘Peter Knolle‘ post ‘upload file component’.
For this post we are using the chunk file upload method, by this chunk file upload method we can upload large file attachments within the heap size limitation, we are using the small 750kb chunks for upload our attachment.
Using this sample code you can upload attachments upto 4.5 Mb.
Lightning Component Output Sample :
Now let’s start code …
Step 1 : Create Apex Controller : FileUploadController.apxc
From Developer Console >> File >> New >> Apex Class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/* * sfdcmonkey.com * 25/9/2017 */ public with sharing class FileUploadController { @AuraEnabled public static Id saveChunk(Id parentId, String fileName, String base64Data, String contentType, String fileId) { // check if fileId id ''(Always blank in first chunk), then call the saveTheFile method, // which is save the check data and return the attachemnt Id after insert, // next time (in else) we are call the appentTOFile() method // for update the attachment with reamins chunks if (fileId == '') { fileId = saveTheFile(parentId, fileName, base64Data, contentType); } else { appendToFile(fileId, base64Data); } return Id.valueOf(fileId); } public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType) { base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8'); Attachment oAttachment = new Attachment(); oAttachment.parentId = parentId; oAttachment.Body = EncodingUtil.base64Decode(base64Data); oAttachment.Name = fileName; oAttachment.ContentType = contentType; insert oAttachment; return oAttachment.Id; } private static void appendToFile(Id fileId, String base64Data) { base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8'); Attachment a = [ SELECT Id, Body FROM Attachment WHERE Id =: fileId ]; String existingBody = EncodingUtil.base64Encode(a.Body); a.Body = EncodingUtil.base64Decode(existingBody + base64Data); update a; } } |
- see code comments.
Step 2 : Create Lightning Component: fileUpload.cmp
From Developer Console >> File >> New >> Lightning Component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<!-- * sfdcmonkey.com/ Piyush Soni * Date : 25/9/2017 * Locker Service Ready. --> <aura:component controller="FileUploadController"> <!-- 'parentId' Aura Attribute for store the Id for Parent Record where we are attach our file --> <aura:attribute name="parentId" type="Id" default="0016F000024nYzwQAE" /> <!-- 'showLoadingSpinner' attribute for show/hide the uploading image and msg in aura:if--> <aura:attribute name="showLoadingSpinner" type="boolean" default="false" /> <!-- 'fileName' attribute for display the selected file name --> <aura:attribute name="fileName" type="String" default="No File Selected.." /> <!-- Lightning Input with file type and on file change call the 'handleFilesChange' controller --> <lightning:input aura:id="fileId" onchange="{!c.handleFilesChange}" type="file" name="file" label="Upload Attachment" multiple="false"/> <div class="slds-text-body_small slds-text-color_error">{!v.fileName} </div> <!--use aura:if for show-hide the loading spinner image--> <aura:if isTrue="{!v.showLoadingSpinner}"> <div class="slds-text-body_small slds-text-color_error">Uploading... <img src="/auraFW/resources/aura/images/spinner.gif" class="spinner-img" alt="Loading"/>' </div> </aura:if> <br/> <button class="slds-button slds-button_brand" onclick="{!c.doSave}">Upload Attachment</button> </aura:component> |
- In the above lightning component on line number 10, we have a attribute called ‘parentId’ , in this attribute you have need to set the parent id, in in sample i am using the account id.
- see code comments.
you can select or drag your file in this lightning component
JavaScript Controller : fileUploadController.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* * Source : sfdcmonkey.com * Date : 25/9/2017 * Locker Service Ready code. */ ({ doSave: function(component, event, helper) { if (component.find("fileId").get("v.files").length > 0) { helper.uploadHelper(component, event); } else { alert('Please Select a Valid File'); } }, handleFilesChange: function(component, event, helper) { var fileName = 'No File Selected..'; if (event.getSource().get("v.files").length > 0) { fileName = event.getSource().get("v.files")[0]['name']; } component.set("v.fileName", fileName); }, }) |
JavaScript Helper : fileUploadHelper.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
/* * Source : sfdcmonkey.com * Date : 25/9/2017 * Locker Service Ready code. */ ({ MAX_FILE_SIZE: 4500000, //Max file size 4.5 MB CHUNK_SIZE: 750000, //Chunk Max size 750Kb uploadHelper: function(component, event) { // start/show the loading spinner component.set("v.showLoadingSpinner", true); // get the selected files using aura:id [return array of files] var fileInput = component.find("fileId").get("v.files"); // get the first file using array index[0] var file = fileInput[0]; var self = this; // check the selected file size, if select file size greter then MAX_FILE_SIZE, // then show a alert msg to user,hide the loading spinner and return from function if (file.size > self.MAX_FILE_SIZE) { component.set("v.showLoadingSpinner", false); component.set("v.fileName", 'Alert : File size cannot exceed ' + self.MAX_FILE_SIZE + ' bytes.\n' + ' Selected file size: ' + file.size); return; } // create a FileReader object var objFileReader = new FileReader(); // set onload function of FileReader object objFileReader.onload = $A.getCallback(function() { var fileContents = objFileReader.result; var base64 = 'base64,'; var dataStart = fileContents.indexOf(base64) + base64.length; fileContents = fileContents.substring(dataStart); // call the uploadProcess method self.uploadProcess(component, file, fileContents); }); objFileReader.readAsDataURL(file); }, uploadProcess: function(component, file, fileContents) { // set a default size or startpostiton as 0 var startPosition = 0; // calculate the end size or endPostion using Math.min() function which is return the min. value var endPosition = Math.min(fileContents.length, startPosition + this.CHUNK_SIZE); // start with the initial chunk, and set the attachId(last parameter)is null in begin this.uploadInChunk(component, file, fileContents, startPosition, endPosition, ''); }, uploadInChunk: function(component, file, fileContents, startPosition, endPosition, attachId) { // call the apex method 'saveChunk' var getchunk = fileContents.substring(startPosition, endPosition); var action = component.get("c.saveChunk"); action.setParams({ parentId: component.get("v.parentId"), fileName: file.name, base64Data: encodeURIComponent(getchunk), contentType: file.type, fileId: attachId }); // set call back action.setCallback(this, function(response) { // store the response / Attachment Id attachId = response.getReturnValue(); var state = response.getState(); if (state === "SUCCESS") { // update the start position with end postion startPosition = endPosition; endPosition = Math.min(fileContents.length, startPosition + this.CHUNK_SIZE); // check if the start postion is still less then end postion // then call again 'uploadInChunk' method , // else, diaply alert msg and hide the loading spinner if (startPosition < endPosition) { this.uploadInChunk(component, file, fileContents, startPosition, endPosition, attachId); } else { alert('your File is uploaded successfully'); component.set("v.showLoadingSpinner", false); } // handel the response errors } else if (state === "INCOMPLETE") { alert("From server: " + response.getReturnValue()); } else if (state === "ERROR") { var errors = response.getError(); if (errors) { if (errors[0] && errors[0].message) { console.log("Error message: " + errors[0].message); } } else { console.log("Unknown error"); } } }); // enqueue the action $A.enqueueAction(action); } }) |
- see code comments.
From developer console >> file >> new >> Lightning Application
demo.app [Lightning Application]
1 2 3 4 5 6 7 8 |
<aura:application extends="force:slds"> <c:fileUpload/> <!-- here c: is org. default namespace prefix--> </aura:application> |
Output:
Related Resource:
Like our facebook page for new post updates. & Don’t forget to bookmark this site for your future reference.
if you have any suggestions or issue with it, you can share your thoughts in comment box.
Happy Learning 🙂
48 comments
Is there a way to display the attached file in the attachments tab in Lightning?
Hi Friends,
I have one doubt, I am using document object for profile pictures it is not allowing more than 1 Mb file in side the Salesforce. I want to increase capacity from 1 Mb to 4 Mb please tell how can I achieve that.
Here given below link which I am using for picture upload.
https://developer.salesforce.com/blogs/developer-relations/2015/11/create-lightning-component-drag-drop-profile-pictures.html
Please help me where I need to do changes for 4 Mb file uploading
Thanks in Advance.
Regards,
Rajesh
Hi Team,
What is the maximum file size that we can upload?
I have tried and observed that we can upload only maximum of 4.5MB file, As there is an exception being thrown from apex i.e. Heap Exception on string value is crossing 6MB.
Is there any other alternative way that we can upload file of more than 5MB?
Absolutly right. From Apex you can upload only 4.5 Mb attachments. It depends on heap size limit for String class (6Mb). Because we using base64 encoding we will take only 6*0.75=4.5Mb. But If you can upload file from 3-party server this size will grow. I want tell about Rest API. For Attachment limit is 25Mb. If you choise Document you can upload up to 2Gb. If you choise other Object with Blob field it is only 500Mb.
Hi Guys,
The above code is not working for me. I mean it is not throwing any exception at the same time all the time the spinner is rendering and attachment also not get created in Salesforce.
Please let me know. Thanks!
Hi Team,
The above code is not working for me. When I have upload a image all the time spinner is rendering and image also not inserting in side the salesforce. Please let me know. Thanks!
Hi ravi,
are you using same code as above ? and try to debug code using console.log()
Hi piyush
Is There any way to upload files above 4.5 Mb(Upto 10 Mb). The above code is working perfectly fine upto 4.5 Mb
Test Class for this?
HI sam, kindly put your issue related to test class here :
https://developer.salesforce.com/forums#!/feedtype=RECENT&criteria=ALLQUESTIONS&
The Person who made this blog , you are the Legend.
Thanks for your valuable feedback @jet R 🙂
This component I have used in a FSL Mobile flow. It works fine in SF1 and Desktop but isn’t working in FSL mobile app. It just shows an input text. Any clue?
It is not working. From last 1 hour spinner is rotating. the attachment is not saved in any object
Update the ParentId from the code above to the object ID to which you want to save the attachment and it should work. Thanks.
Thank you, now we can save the code into object but we should hard code the id of account object.can you please guide me.
Hi Everyone,
Can you help me to use this component to upload attachment before saving the record.
The scenario is the user has to upload the document while creating the record.
I updated all classes from parentId to caseId. But i get an error on line 27 “Variable does not exist: caseId”
How can I pass a flow variable into the controller where you have hard coded the account id? Please help me, I am stuck at this point.
Hi Piyush,
Could you please help me, I want to replace parentId with the dynamic caseid from my flow. How can I accomplish this to pass flow output variable to this lightning component.
Regards
Chetan Bhatla
I got it working, getting a flow variable into this lighning component. Thanks for this amazing article. this solved my problem of attaching a file with the case by community guest user who does not have Edit access on case object.
Thanks Again.
Hello,
You can include a attribute called as accept in the lightning:input tag. By this way you can restrict the types of attachments that can be uploaded. Also you can specify if you need to access the camera on a smatrphone or a tablet using the salesforce1 app or also if salesforce is opened from a mobile browser. This is a very good use case for service engineers to capture images on the go and upload it to any record.
Hi Nitesh,
i want to accomplish kind of same you mentioned, i am creating a Component to create Account Record in which i want to get the image as well, for that i have tried (Lightning:upload) but it does not have (onClick) attribute so i decided to build custom upload with this article but i am unable to save the component it throws an error
“Failed to save fileUploader.cmp: Invalid definition for FileUploaderController: ApexService.getType() return null with currentNamespace: c, namespace: null, name: FileUploaderController: Source ”
can you help me with that?
I want to upload more than 1GB file, based on Chunks, is there any solution or proper way to devlope the code throght lightning component apex.
Hi,
Is it possible to upload to Files?
Thank you.
private static void appendToFile(Id fileId, String base64Data) {
base64Data = EncodingUtil.urlDecode(base64Data, ‘UTF-8’);
Attachment a = [
SELECT Id, Body
FROM Attachment
WHERE Id =: fileId
];
String existingBody = EncodingUtil.base64Encode(a.Body);
a.Body = EncodingUtil.base64Decode(existingBody + base64Data);
update a;
}
hi piyush i need test class for this method could you please provide if possible…thanks
Hi ,
I am using the above code to save attachment.After inserting it is returning attachment but when i query the record with the returned Id it is giving me zero results.FileId is not null.
Attachment a = [
SELECT Id, Body
FROM Attachment
WHERE Id =: fileId
];
Can you please let me know if it is still pending or why is it returning zero results?
Thanks
Hi ,
I am using the above code. After inserting attachment it is returning Id, but when I fetch the record by SOQL query it is returning me no records.
Attachment a = [
SELECT Id, Body
FROM Attachment
WHERE Id =: fileId
];
Can you please let me know why is it returning zero records?Is it still pending for insertion
Action failed: c:fileuploading$controller$doSave [Cannot read property ‘length’ of null]
Thanks Piush. You are absolutely a legend !!!. From your blog, I have learned a lot in lightning 🙂
There is an error received when I am trying to upload the file using the above code.
Uncaught TypeError: Cannot read property ‘setParams’ of undefined throws at https://dev6-ecolabpestelimination.cs83.force.com/components/c/PRTL_FileUpload.js:55:16
which is actually the action.setParams({ in my helper.
The file action is set to null why?
There is an error received when I am trying to upload the file using the above code.
Uncaught TypeError: Cannot read property ‘setParams’ of undefined throws at https://dev6-ecolabpestelimination.cs83.force.com/components/c/PRTL_FileUpload.js:55:16
which is actually the action.setParams({ in my helper.
The file action is set to null why?
Hi Piush,
This code worked for me, but only upto 4.5MB files are uploading. Is there any way to upload bigger files like (10-25MB) files.
Thanks
Hi Piush,
This code worked for me, but only upto 4.5 files are uploading is there any way to upload bigger files like (10-20MB) files.
Thanks
HI,
The above code is not working for file size of 1.8Mb. Its Giving Heap Size error.
Hi Piush,
I am getting heap size error when uploading file of size 1.8MB.
Hi ,
I want to Parse the Excel file using lightning component.Please do the needful.
Regards,
Ashish
Hi Piyush,
I want to have the same kind of functionality but i want to save the browsed image to document object.how can i do that?
Hi Piyush,
your checking the file size in helper.it is not working properly
if (file.size > self.MAX_FILE_SIZE) {
component.set(“v.showLoadingSpinner”, false);
component.set(“v.fileName”, ‘Alert : File size cannot exceed ‘ + self.MAX_FILE_SIZE + ‘ bytes.\n’ + ‘ Selected file size: ‘ + file.size);
return;
}
here i want restrict the file size is 3mb.its not working properly.
Hello Peter Knolle,
I Used this Code its working fine,but When i Upload a file of 3.5 Mb file Apex heap size too Large.getting Error but File is not opened.
Can this code work for standalone lightning component?
I have registeration form,i need to attach resume upload functionality to it. But your code doesnt work , as it keep spinnng and file never saves.
Hi. Files gets uploaded but it is showing in Documents tab. Can you please assist me on this
Hi. Piyush,,
Im using the above code and created custom case componets but im unable to attch files morethen 2 Mb Pdf or ther files. Spinner shoulf be loading after 2MB files loaded. It works fime for small files below 1. 5 Mb. How can it work for others to uplaod upto 4.5 Mb. Any one tell me plz…. And ho can we increase upto 10 mb
Thank you
Emran
now you can simply use lightning:fileupload component
HI, Piyush
by using this code im unable to upload file more then 1.5 mb, but you said limit is 4.5 mb, if i upload filesize morethen 2mb spinner should loading and file not attached, the debug log says apex heap size limit is more then the limit. how can we resolve this issue. pls update me
Thank you
emran
File saved in the attachment but i am unable to open it. Please let me know what is the issue??
Thanks
Jatin Puri
I am creating a Component to create Account Record in which i want to get the image as well, for that i have tried (Lightning:upload) but it does not have (onClick) attribute so i decided to build custom upload with this article but i am unable to save the component it throws an error
“Failed to save fileUploader.cmp: Invalid definition for FileUploaderController: ApexService.getType() return null with currentNamespace: c, namespace: null, name: FileUploaderController: Source ”
can you help me with that?