A blog about Salesforce CRM Configuration and development

Saturday, 13 October 2018

Upload multiple files through Visualforce page

Upload Multiple files with the progress bar.



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...
Share:

26 comments:

  1. Hi 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 ?

    ReplyDelete
  2. Hi 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?

    ReplyDelete
    Replies
    1. Hello Deepak,

      I 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.

      Delete
  3. Hi Arun,

    I 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..

    ReplyDelete
    Replies
    1. Hello Deepak,

      You 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;

      Delete
    2. 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!

      Delete
    3. Hi Arun, How can I get this idSet to be passed from JS to apex controller?

      Delete
  4. Hi Arun,

    Thanks 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.

    ReplyDelete
  5. Deepak, I have tested with file size 15 MB and it uploaded successfully.

    What problem/error you are getting while uploading this file? You can attach up to 2 GB file size through Salesforce Files object.

    ReplyDelete
  6. Hi Arun,

    Need 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.

    ReplyDelete
  7. 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:

    Access 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.

    ReplyDelete
    Replies
    1. Hi Arun,

      Anything 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.

      Delete
  8. Hi,

    This 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?

    ReplyDelete
    Replies
    1. Hello,

      Have you checked the sessionId? is this available or not.

      The user must have the permission on objects and to upload the file.

      Thanks

      Delete
    2. I am also facing the same issue. Do you find any solution?

      Delete
  9. Thanks a lot for such a wonder full peace of code

    ReplyDelete
  10. Hie Arun Do i need to change anything to get the work Done??

    ReplyDelete
  11. Hi Arun,

    Please 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

    ReplyDelete

Trailhead Profile


Follow by Email

Total Pageviews

Followers

Popular Posts

Powered by Blogger.

Contact form

Name

Email *

Message *