Upload Multiple files with the progress bar.
On 'Upload' button click this method will be called. Here '#uploadBtn' is the id of the button.
This success function will return the success message with the ids of the file that just uploaded.
References:
XML Http Request
AJAX Method
ContentVersion
Hope this blog post will help many.
Happy coding...
While uploading the multiple files at the same time you may have faced the problem like 'View state size limit exceeded', 'Heap size' limit and file size limit. To overcome these limits we can use javascript to handle the file uploading through the Visualforce page.
I have also faced the problem like View state size limit exceeded and Heap size limit, to solve the issue I decided to send/upload the files using HTTP POST Request with the help of Ajax, Jquery, javascript. Below is the code snippet for uploading files in the ContentVersion object.
<apex:page> <html> <head> <apex:slds /> <apex:includeScript value="https://code.jquery.com/jquery-2.2.4.js"/> <script> //function starts $(function(){ var fileLenght=0; $('#uploadBtn').click(function() { var v=document.getElementById('addr'); console.log(v.files.length); fileLenght = v.files.length; for (var i = 0; i < v.files.length; i++) { uploadSelectedFile(v.files[i], function(err, res){ FileUploading += 1; if (FileUploading === FileUploaded){ alert('upload completed'); //blank input file value document.getElementById("addr").value = ""; } }) } }); var FileUploading = 0; var FileUploaded = 0; var ids = new Array(); var uploadSelectedFile = function(file, callback) { filetoBase64(file, function(err, content){ var conVer_object = { ContentLocation : 'S', VersionData : content, PathOnClient : file.name, Title : file.name }; $.ajax({ url: '/services/data/v39.0/sobjects/ContentVersion', data: JSON.stringify(conVer_object ), type: 'POST', processData: false, contentType: false, headers: {'Authorization': 'Bearer {!$Api.Session_ID}', 'Content-Type': 'application/json'}, xhr: function(){ var xhr = new window.XMLHttpRequest(); //Upload progress xhr.upload.addEventListener("progress", function(evt){ if (evt.lengthComputable) { $('#progress_bar_container').css('display', 'block'); var percentComplete = evt.loaded / evt.total; console.log('percentComplete '+percentComplete ); var percentCompletex= percentComplete*100; $('#percentText').html("Uploading. Please wait... "+Math.round(percentCompletex)+"%"); $('.progress').css('width', percentCompletex+ "%"); if(percentCompletex == 100){ $('#progress_bar_container').css('display', 'none'); } } }, false); return xhr; }, success: function(response) { FileUploaded += 1; console.log(response.id); // the id of the attachment ids.push(response.id); console.log('Ids: ' +ids); $('#records').html('File has been uploeded. Uploaded File ids: ' +ids); if(fileLenght == FileUploaded ){ //calculateLocation(ids.toString()); } callback(null, true) }, }); }); } //Read file var filetoBase64 = function(file, callback){ var reader = new FileReader(); reader.onload = function() { var myFileContents = reader.result; var base64Mark = 'base64,'; var dataStart = myFileContents.indexOf(base64Mark) + base64Mark.length; myFileContents = myFileContents.substring(dataStart); callback(null, myFileContents); } reader.readAsDataURL(file); } }); </script> <style> .slds-scope .slds-page-header{ border-radius: 0px; box-shadow: 0 0px 0px 0 rgba(0, 0, 0, 0.1); } .bodyPart{ padding:10px; } </style> </head> <body> <apex:form > <div class="slds" style="border:1px solid #D9D9D9;"> <div class="slds-page-header"> <span style=""> Upload Files</span> </div> <div id="progress_bar_container" style="display:none; padding:10px;"> <span id="percentText"></span> <div class="slds-progress-bar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="25" role="progressbar"> <span class="slds-progress-bar__value progress" style=" width: 0%;"> <span class="slds-assistive-text">Progress: 25%</span> </span> </div> </div><br/> <div class="bodyPart"> Select file: <input type="file" name="files[]" multiple="multiple" id="addr"/> <input type="button" id="uploadBtn" name="Address" value="Upload" class="slds-button slds-button--brand"></input> </div> <div id="uploadedrec" style="padding:10px;"> <span id="records" style=" color:green; "> </span> </div> </div> </apex:form> </body> </html> </apex:page>
On 'Upload' button click this method will be called. Here '#uploadBtn' is the id of the button.
$('#uploadBtn').click(function() { ...}
If the user selects multiple files, Iterating over files length. for (var i = 0; i < v.files.length; i++) { ... }
In every iteration uploadSelectedFile, JS function will be called. uploadSelectedFile(v.files[i], function(err, res){ ...}
Reading the files and converted into the base64 format. filetoBase64(file, function(err, content){ }
ContentVersion object variable with required fields. var conVer_object = {
ContentLocation : 'S',
VersionData : content, // File body
PathOnClient : file.name, // File name
Title : file.name //File title
};
This AJAX method used to perform the asynchronous HTTP request to Salesforce. $.ajax({ ... }
URL or Endpoint: HTTP POST method will post the content to the specified location (ContentVersion object). url: '/services/data/v39.0/sobjects/ContentVersion',
Header: Salesforce Session_ID used for authentication. headers: {'Authorization': 'Bearer {!$Api.Session_ID}', 'Content-Type': 'application/json'},
XML HttpRequest object: Send the data from page to server (Salesforce) in the background. var xhr = new window.XMLHttpRequest();
The addEventListener function listen to the progress of uploading. xhr.upload.addEventListener("progress", function(evt){ ... }
These lines of code will display the Progress bar on the page. $('#progress_bar_container').css('display', 'block');
var percentComplete = evt.loaded / evt.total;
console.log('percentComplete '+percentComplete );
var percentCompletex= percentComplete*100;
$('#percentText').html("Uploading. Please wait... "+Math.round(percentCompletex)+"%");
$('.progress').css('width', percentCompletex+ "%");
if(percentCompletex == 100){
$('#progress_bar_container').css('display', 'none');
}
This success function will return the success message with the ids of the file that just uploaded.
success: function(response) { ... }
Output:References:
XML Http Request
AJAX Method
ContentVersion
Hope this blog post will help many.
Happy coding...
Great one
ReplyDeleteglad you liked it. 🙂
Deletebahut acha arun.! :) (y)
ReplyDeleteThank You! ☺️
DeleteVery nice arun
ReplyDeleteThanks 🙂
DeleteHi Arun, i want to be able to upload document into Sharepoint using named credentials from salesforce. I am hit with 4.5mb limit. How we do bypass the head memory limit ?
ReplyDeleteHi Arun,i have gone through your blog and its great but i am unable to upload docx and csv files. How can we overcome this?
ReplyDeleteHello Deepak,
DeleteI just checked the '.docx' and '.csv' file and i am able to upload these files. After file upload you will get the file record id, you can see the file using this id. Let me know what problem you are getting while uploading these files.
Hi Arun,
ReplyDeleteI got different requirement now where the files your uploading needs to be stored under File object but as related list in Opportunity object. I am associating Opportunity object here and whenever user uploads any files the file should be visible under Opportunity object as related list.
I tried a lot with using Apex controller but couldn't achieve can you help me out here..
Hello Deepak,
DeleteYou have to link the file to the object (Opportunity) after upload. You can do it in Apex controller like code below.
//idSet -->you will get this ids after file upload already. Send the ids from vf page to apex.
List contentVerList = [select id,contentDocumentId, Title from ContentVersion where Id IN:idSet ];
set contentDocIds = new set();
for(ContentVersion cv: contentVerList ){
contentDocIds.add(cv.ContentDocumentId);
}
List cdl = new List();
for(Id contentDocumentId: contentDocIds){
//Create ContentDocumentLink
ContentDocumentLink cDe = new ContentDocumentLink();
cDe.ContentDocumentId = contentDocumentId;
cDe.LinkedEntityId = OpportunityId; // you can use objectId,GroupId etc
cDe.ShareType = 'V'; // Inferred permission, checkout description of ContentDocumentLink object for more details
cdl.add(cDe);
}
insert cdl;
Hi Arun, hope you can help me! I also need to upload to another object (Case), but as guest user from unauthenticated login to community (public access disabled). I'm not sure how to incorporate the above code snippet to the VF page, or controller - I am still learning the coded side of SF. Is this the complete code to be inserted? Thanks in advance!
DeleteHi Arun, How can I get this idSet to be passed from JS to apex controller?
DeletePlease reply me ASAP.
ReplyDeleteHi Arun,
ReplyDeleteThanks for your quick reply the solution worked for me.Your a true life saver..
One last question what is the size limit of uploading documents. Becuase i am unable to upload 6 MB pdf file.
Deepak, I have tested with file size 15 MB and it uploaded successfully.
ReplyDeleteWhat problem/error you are getting while uploading this file? You can attach up to 2 GB file size through Salesforce Files object.
Hi Arun,
ReplyDeleteNeed one small help. The progress bar which is shown up in your code is not being displayed if user is uploading single file and the progress bar runs very quickly. Is there any way by which we can control this variation.
And also after i have uploaded 1 file and immediately try to upload one more file Upload Button is not getting called and i am getting following error:
ReplyDeleteAccess to XMLHttpRequest at 'https://kmpl--twlosdev.cs76.my.salesforce.com/_ui/common/request/servlet/JsLoggingServlet' (redirected from 'https://kmpl--twlosdev--c.cs76.visual.force.com/_ui/common/request/servlet/JsLoggingServlet') from origin 'https://kmpl--twlosdev--c.cs76.visual.force.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Hi Arun,
DeleteAnything on above question asked.. I am using this functionality in one our live projects so need help in implementing it fully.
Please let me know answers to above question.
Hi,
ReplyDeleteThis works as expected for the logged in user. However, for when using through a force.com site, this gives 503 error. Do you have an idea how to solve this?
Hello,
DeleteHave you checked the sessionId? is this available or not.
The user must have the permission on objects and to upload the file.
Thanks
I am also facing the same issue. Do you find any solution?
DeleteThanks a lot for such a wonder full peace of code
ReplyDeleteGlad you liked it.
DeleteHie Arun Do i need to change anything to get the work Done??
ReplyDeleteHi Arun,
ReplyDeletePlease kindly help, does this work for sites.com VF page. I'm implementing it on a live project. Will be grateful if you can help me on this