0

I built a lightning component (incl. Controller, Apex-Controller and Helper) I want to use for excel file uploads (and importing the records to a custom object). In the Helper, I am creating a FileReader having an eventHandler onload in which I was already successfully able to access the different Objects Columns and Rows. But when I try to make use of the component.set or the results in general (eg. in order to give it back to my list attribute or simply using a console.log() to show the results outside this onload eventHandler, the result is gone. (For sake of completeness I also added the Apex controller which should in the end save the content to the custom object) I think there are kind of similar issues around (https://stackoverflow.com/questions/27254735/filereader-onload-with-result-and-parameter), but I am not really finding the root cause.

Component

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" controller="UploadController" >

    <aura:attribute name="customObject" type="List" />

<ltng:require scripts="{!$Resource.Xlsx_1234}" />

    <lightning:layoutItem size="6" padding="around-small">

        <lightning:layout multipleRows="false" horizontalAlign="end" verticalAlign="end">


            <lightning:layoutItem flexibility="grow" size="4" padding="around-small">
                <lightning:input aura:id="uploader" type="file" label="." variant="label-hidden" name="file" multiple="false" onchange="{!c.onFileUploading}"
                                 accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"/>


            </lightning:layoutItem>


    </lightning:layoutItem>

    <lightning:layoutItem size="6" padding="around-small" />

Controller

({

onFileUploading : function(component, event, helper) {

     let file = event.getSource().get('v.files')[0];
     helper.handleFileUploaded(component, file);

onSaveCreateToQuoteOnClick: function(component, event, helper) {

            helper.insertCustomObject(component);
    }

})

Helper

({
handleFileUploaded: function(component, file) {
        const MAX_FILE_SIZE = 750000;
        let self = this;

        //excluded some validation here

        let fr = new FileReader();
        var arr = [];

        fr.onload = function() {
            let fileContents = fr.result;
            let workbook = XLSX.read(fileContents, {
                type: 'binary'
            });

            let rows = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);

            let customObjects = [];

            //at this point trying to access/view JSON Objects content via console.log works
            //below is some other accessing the object

            for (let i = 0, len = rows.length; i < len; i++) {

                for (let j = 1; j <= 5; j++) {
                    let customObject = {
                        sobjectType: 'customObject__c',
                        Name: rows[i]['Name'],
                        Value1__c: rows[i]['Value1']
                    };

                    let key = 'Value2';

                    if (!$A.util.isEmpty(rows[i][key + j])) {
                        customObject.Value2__c = key + j;
                        customObject.Value3__c = rows[i][key + j];
                    }
                    customObjects.push(customObject);
                }
            }
            //here the results for the customObject excel import file should be stored in the attribute variable of the component
            //it is not working, seems as the result vanishes after eventHandler closes...
            component.set("v.customObject", customObjects);
        };

        fr.readAsBinaryString(file);

        //trying to add result to variable for output in console
        //nothing showing in console here either
        component.set("v.customObjects", customObjects)
        let something = component.get("v.customObjects");
        console.log(something);

},

insertCustomObjects: function(component, file) {

    let customObjects = component.get("v.customObjects");

    var action = component.get("c.saveCustomObjects");
                action.setParams({
                    "customObjects": customObjects
                });

                action.setCallback(this, function(a) {
                       var state = a.getState();
                        if (state === "SUCCESS") {
                            var name = a.getReturnValue();
                            alert("PERSISTED");
                        }
                        if (state === "ERROR") {
                                                var name = a.getReturnValue();
                                                }
                    });
                $A.enqueueAction(action)
} })

Apex Controller

public with sharing class CustomObjectController {

@AuraEnabled
public static void saveCustomObjects (List<CustomObject__c> customObjects) { 

    insert customObjects
} }

2 Answers 2

2

Any time you use a native Javascript callback instead of an Aura callback, you need to wrap your function in $A.getCallback. If you don't do this, your callback doesn't run in the right context for Aura, and you might find things like reading/writing to components fails.

So, where you have

fr.onload = function() {
...
};

You should have

fr.onload = $A.getCallback(function() {
...
});

See https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_cb_mod_ext_js.htm

4
  • I added the getCallback, but it appears if the push won't push any values and the Array remains empty unfortunately. The lightning attribute customObject of type List remains therefore empty. Using console.log(component.get("v.customObjects") will not return anything: Proxy [[Handler]]: Object [[Target]]: Array(0) [[IsRevoked]]: false Or is there a better way to test it/Is my syntax incorrect?
    – Cmd_Keen
    Commented Mar 18, 2019 at 11:35
  • btw: of course the attribute <aura:attribute name="customObject" type="List" /> should be called customObjects (plural, I changed it in my code)
    – Cmd_Keen
    Commented Mar 18, 2019 at 11:36
  • fr.readAsBinaryString(file); is asynchronous. So, you can't just call that and then read the results on the next line. You need to chain things via your onload callback. A common thing to do in Lightning would be to call the helper function which ought to write to the Apex controller from the end of onload.
    – Aidan
    Commented Mar 18, 2019 at 13:34
  • yes, you are right, I added a datatable to the view, set it up in the controller and feed it with the v.customObject. This works now. Thanks
    – Cmd_Keen
    Commented Mar 18, 2019 at 15:04
0

Can you please change attribute type of the attribute customObject from List to Object[] and then do component.set("v.customObject", customObjects); and check.

2
  • Object attribute type in lightning is not same as in JavaScript
    – Raul
    Commented Mar 18, 2019 at 11:06
  • unfortunately, this didn't help.
    – Cmd_Keen
    Commented Mar 18, 2019 at 11:31

You must log in to answer this question.

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