2

I have developed a lightning component to upload files into the File Salesforce object.

This component has been developed based on Peter Knolle article on how to do that in the lightning framework.

This component has been working good for over a year - until 2 weeks ago (maybe Winter 18 is the cause of the change).

The problem is that I create an action to send to the server, set it's params, set it's callback, and then use the $A.enqueueAction(action); command.

Now - the action is queued but not executing.

I have used the chrome lightning inspector extension and the action is clearly pending:

enter image description here

And it is stuck forever, unless I close the component or something like that.

This is my component:

FileUpload.cmp

<aura:component controller="Attachment_CTRL">

    <aura:attribute name="parentId" type="Id"/>
    <aura:attribute name="fileMetadata" type="Object" description="the metadata of the file that was uploaded to the client - before saving to server" access="private" />
    <aura:attribute name="fileData" type="Object" description="the actual file that was uploaded to the client - before saving to server" access="private"/>


    <aura:method name="executeUpload" action="{!c.executeUpload}" description="Fire the executeUpload controller method">
        <aura:attribute name="fileMetadata" type="Object" />
        <aura:attribute name="fileData" type="Object"/>
    </aura:method>

    <div class="slds-form-element" title="max 750 Kb">
        <div class="slds-form-element__control">
            <div class="slds-file-selector slds-file-selector--files">
                <input class="slds-file-selector__input slds-assistive-text" type="file" onchange="{!c.save}" aura:id="file" id="file-upload-input-01" aria-describedby="file-selector-id" />
                <label class="slds-file-selector__body" for="file-upload-input-01">
                    <span class="slds-file-selector__button slds-button slds-button--neutral">
                        <lightning:icon iconName="utility:add" size="x-small" />&nbsp;Add File&nbsp;
                    </span>
                </label>
            </div>
        </div>

    </div>

    <lightning:spinner aura:id="uploadingSpinner" size="large" class="slds-hide" />

</aura:component>

FileUploadController.js

({
    //    MAX_FILE_SIZE: 750000, /* 1 000 000 * 3/4 to account for base64 */
    save: function(component, event, helper) {
        var fileInput = component.find("file");
        var fileElement = fileInput.getElement();
        var fileMetadata = fileElement.files[0];

        if (fileMetadata.size > 750000) {
            alert("File size is too big!!!");
            return;
        }

        var fr = new FileReader();
        fr.onload = function() {
            var fileData = fr.result;
            var base64Mark = 'base64,';
            var dataStart = fileData.indexOf(base64Mark) + base64Mark.length;
            fileData = fileData.substring(dataStart);

            // TODO: this aura:method is used because straight server side call does not execute from within FileReader
            // call server through aura:method to override server action not executing problem
            component.executeUpload(fileMetadata, fileData);
        };
        // run file reader for downloading file
        fr.readAsDataURL(fileMetadata);
    },
    executeUpload: function(component, event, helper) {

        var params = event.getParam('arguments');
        if (params) {
            var fileMetadata = params.fileMetadata;
            var fileData = params.fileData;
            var parentId = component.get("v.parentId");

            helper.uploadFile(component, fileMetadata, fileData, parentId);
        }
    }
})

FileUploadHelper.js

({
    uploadFile: function(component, fileMetadata, fileData, parentId) {

        // get server side method
        var action = component.get("c.upload"); 

        // set all file params
        action.setParams({
            parentId: parentId,
            fileName: fileMetadata.name,
            base64Data: encodeURIComponent(fileData),
            contentType: fileMetadata.type
        });

        // set the callback function        
        action.setCallback(this, function(response) {

            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                alert("File uploaded successfully");
            }
            else { // tell parent file was not added:
                alert("Error uploading file");
            }

            // turn spinner off - after finished uploading
            this.toggleSpinner(component);
        });

        // execute server side action
        $A.enqueueAction(action);   
    },  

    toggleSpinner: function(component) {
        var spinner = component.find("uploadingSpinner");
        $A.util.toggleClass(spinner, "slds-hide");
    }
})

Attachment_CTRL.cls

public without sharing class Attachment_CTRL {
    @AuraEnabled
    public static Id upload(Id parentId, String fileName, String base64Data, String contentType) {

        system.debug('Attachment_CTRL.upload start for Id: ' + parentId + ', file name: ' + fileName);

        String decodedData = EncodingUtil.urlDecode(base64Data, 'UTF-8');
        Blob body = EncodingUtil.base64Decode(decodedData);

        Attachment newAttachment = new Attachment();
        newAttachment.parentId = parentId;
        newAttachment.Name = fileName;
        newAttachment.Body = body;
        newAttachment.ContentType = contentType;

        insert newAttachment;

        return newAttachment.Id;
    }
}

My question is: am I doing something wrong? why is the action not executing? how can I fix this and execute the action?

4
  • did you consider using the new lightning:fileUpload?
    – itsmebasti
    Oct 24, 2017 at 8:21
  • 1. Does the issue happen for all the files or is there is a work scenario? 2. Can you check your storage statistics ?
    – Sumuga
    Oct 24, 2017 at 8:56
  • @Batsi - I am working within a VF page using lightning out and lightning:fileUpload is not supported there Oct 24, 2017 at 8:59
  • @Samuga this is happening allways - with every server call, also not a file related server call, so this problem is not related to the file sending Oct 24, 2017 at 9:09

1 Answer 1

4

fr.onload = function() { ..} should be using fr.onload = $A.getCallback(function() { ..}) to make sure that your callback is run inside the Aura event loop.

That could be why it gets queued but not executed - it wasn't queued quite right as far as Aura is concerned.

I've found these sorts of errors happen unpredictable ways e.g. can work when you're developing, then fail on the next release. Or work on one browser and not on another.

2
  • This is almost certainly the case. The framework doesn't queue up the request from the non-aura context until another interaction happens in the context (like clicking a different button, etc.)
    – dsharrison
    Oct 24, 2017 at 15:38
  • Aidan you are a king!!! It works like a charm, I even do not need the <aura:method name="executeUpload"> anymore. Thanks man! Oct 25, 2017 at 6:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .