[SalesForce] Lightning component action only firing after second button click

I am attempting to create a Lightning Component Custom Action to upload an attachment to a Salesforce record. It is based on Peter Knolle's blog post: http://peterknolle.com/file-upload-lightning-component/

Currently, I am able to select a file, read the file, and queue the 'saveTheFile' action by pressing the Save button. However, the action does not execute (get sent to the server) until I hit the Save button again, at which time the Component processes both actions and uploads two copies of the file.

My question/request is for more insight into why this may happen. I am new-ish to Javascript and the Lightning Component Framework, and my research thus far has proven fruitless.

Below is a simplified version of my code. Thank you in advance for support on my Lightning Component journey!

Component

<aura:component controller="FileController" implements="force:lightningQuickAction,force:hasRecordId,force:appHostable">
<div>
    <input type="file" class="file" aura:id="file" />
    <ui:button label="Save" press="{!c.save}"/>
</div>    
</aura:component>

JS Controller

({  
save : function(component, event, helper) {
    helper.save(component);
},

waiting: function(component, event, helper) {
    console.log('waiting');
},

doneWaiting: function(component, event, helper) {
    console.log('done waiting');
}
})

Helper

({
save : function(component) {
    var fileInput = component.find("file").getElement();
    var file = fileInput.files[0];

    var fr = new FileReader();

    var self = this;
    fr.onload = function() {
        var fileContents = fr.result;
        var base64Mark = 'base64,';
        var dataStart = fileContents.indexOf(base64Mark) + base64Mark.length;

        fileContents = fileContents.substring(dataStart);

        self.upload(component, file, fileContents);
    };

    fr.readAsDataURL(file);
},

upload: function(component, file, fileContents) {
    var action = component.get("c.saveTheFile");

    action.setParams({
        parentId: component.get("v.recordId"),
        fileName: file.name,
        base64Data: encodeURIComponent(fileContents), 
        contentType: file.type
    });

    action.setCallback(this, function(a) {
        var attachId = a.getReturnValue();
    });

    $A.enqueueAction(action);
}
})

Apex Controller

public class FileController {

    @AuraEnabled
    public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType) { 
    base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');

    Attachment a = new Attachment();
    a.parentId = parentId;

    a.Body = EncodingUtil.base64Decode(base64Data);
    a.Name = fileName;
    a.ContentType = contentType;

    insert a;

    return a.Id;
    }
}

I tried wrapping fr.onload inside $A.getcomponent like following.

$A.getCallback(function() {

 fr.onload = function() {

        var fileContents = fr.result;
        var base64Mark = 'base64,';
        var dataStart = fileContents.indexOf(base64Mark) + base64Mark.length;

        fileContents = fileContents.substring(dataStart);

        self.upload(component, file, fileContents,personelIdentType);
      };
});
fr.readAsDataURL(file);

But it seems either syantax for $A.getcomponent() is wrong or i need to do something else.Please help me out.

Best Answer

I had the same issue and it worked by wrapping onload into $A.getCallback()

Related Topic