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.
onload
callback within$A.getCallback()
. Eg:fr.onload = $A.getCallback(function() { ...})
. It might be due to the fact the callback is being called out of Aura's execution context.console.log(attachId,a.getState())
inside the callback of the server action:saveTheFile