I am using the following to upload multiple files in Salesforce custom lightning component. http://sfdcmonkey.com/2017/09/25/file-upload-lightning-component

I my component, I have the following code

<lightning:input aura:id="fileId" onchange="{!c.handleUploadFinished}" type="file" name="file" label="Upload Attachment" multiple="true"/>

In my JS controller I am using the following code

     uploadHelper : function(component, event, helper) {
    var fileInput = component.find("fileId").get("v.files");
    var input = component.get("v.fileList");
    for (var i = 0; i < fileInput.length; i++) { 
        var file = fileInput[i];
        console.log('*****'+file.name);
        var self = this;
        // create a FileReader object 
        var objFileReader = new FileReader();
        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); 
    } 
},

Here in both the console.logs file names, if I upload 2 attachments, file names are being displayed properly for each iteration. However, if I check the uploaded file, I will see one of the files get uploaded twice. What am I doing wrong here

Updated Code

 uploadHelper : function(component, event, helper) {
    var fileInput = component.find("fileId").get("v.files");
    [].forEach.call(fileInput, function(file) { readFile(file); });

},
readFile: function(component, file) {
    var objFileReader = new FileReader();
        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);
},
  • This code is in the controller? Are you sure? I'd expect the upload to fail entirely if this was the case, as this is undefined in a controller. – sfdcfox Nov 8 at 20:24
  • No it does not fail. One of the attachments get uploaded – user55791 Nov 8 at 20:25
up vote 1 down vote accepted

Because of how closures work, the objFileReader is being overwritten each loop, so you're really only referencing the same object by the time the files get loaded. What you need to do is isolate the reader object in its own closure.

readFile: function(component, file) {
  var reader = new FileReader();
  var self = this;
  reader.onload = $A.getCallback(function() {
    ...
  });
  reader.readAsDataURL(file);
},
uploadHelper: function(component, event, helper) {
  var fileInput = component.find("fileId").get("v.files");
  [].forEach.call(fileInput, function(file) { readFile(file); });
},
...

This wasn't covered in the example code, because it presumes that only one file at a time will be selected.

  • I have made changes in the code like you described. But it is not working either. I have updated the changed code in my question above. – user55791 Nov 8 at 21:22
  • No my mistake, it is working correctly. Thanks. – user55791 Nov 9 at 11:39

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.