[SalesForce] How to get Apex list into component controller array variable

I have a component where I define an attribute (forcasts) as an object array. In this case the Saleforce object is named “Forecast_Actuals__c”. These are child records under each Opportunity. The attribute definition is:

<aura:attribute name="forecasts" type="Forecast_Actuals__c[]" />

I have a helper function that calls the apex controller and sets up the callback. I am expecting a list (array) of records to be returned from the Apex controller.

In the Apex controller, after I make the SOQL call I check the list length of my return variable using system.debug (system.debug(FC_List.siz());) and I get a value of 6, which is correct.

In the callback function, I load the response into my forecast variable:

var forecasts = component.get("v.forecasts");
forecasts.push(response.getReturnValue());

Then I check the array length in my helper and it is 1 instead of the 6 I was expecting. If I use console.log(JSON.stringify(forecasts) it prints all of the data from the SOQL call. Again, the array size is 1, so all of the data I returned from the Apex controller was loaded into one element of my variable in my helper controller.

How should I be handling the response in the callback in order to load the record data into an array?

Here's the Component:

<aura:component controller="ForecastController" implements="force:lightningQuickAction,flexipage:availableForAllPageTypes,force:hasRecordId">
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>

    <aura:attribute name="forecastdate" type="Date" />
    <aura:attribute name="recordId" type="Id" />
    <!-- 'forecasts' is an array of records from the database -->
    <aura:attribute name="forecasts" type="Forecast_Actuals__c[]" />
    <aura:attribute name="updatedForecast" type="Forecast_Actuals__c[]"/>
    <aura:attribute name="previousActuals" type="Forecast_Actuals__c[]"/>

    <lightning:card iconName="action:new_event">
        <aura:set attribute="title">
            12 Month Forecast, PMXXXX
            <div class="demo-only demo-only--sizing slds-grid slds-wrap">
                <div class="slds-size_1-of-2">
                    <lightning:input type="Date" label="Start Date (mm/dd/yyyy)" name="startdate" onchange="{!c.dateChanged}" value="{!v.forecastdate}" />
                </div>
            </div>
        </aura:set>
        <c:forecastMonth />
    </lightning:card>
</aura:component>

Here's the Apex Controller:

public with sharing class ForecastController {

    @AuraEnabled
    public static List<Forecast_Actuals__c> getForecastActuals(Id recordId, String queryStartDate, String queryStopDate){
        List<Forecast_Actuals__c> FC_List;
        Date StartMonth;
        Date StopMonth;

        StartMonth = Date.valueOf(queryStartDate);
        StopMonth = Date.valueOf(queryStopDate);

        //FC_List = [Select Name from Forecast_actuals__c where Opportunity__c = :recordId];
        FC_List = [select name, FA_External_ID__c, Opportunity__c, x1st_Day_of_Forecast_Month__c, Forecast_Quantity_for_Month__c, Forecast_Sell_Price_for_Month__c from Forecast_Actuals__c where (Opportunity__c =: recordId) AND (x1st_Day_of_Forecast_Month__c >= :StartMonth) AND ( x1st_Day_of_Forecast_Month__c <= :StopMonth) order by x1st_Day_of_Forecast_Month__c ASC];

        system.debug(FC_List);
        system.debug(FC_list.size());
        return FC_List;
    }
}

And here's the helper controller with the callback:

({
    getRecords : function(component, recordId, forecastdate) {
        var queryStartDate = (parseInt(forecastdate.slice(0,4))-1).toString() + forecastdate.slice(4,10);
        var queryStopDate = (parseInt(forecastdate.slice(0,4))+1).toString() + forecastdate.slice(4,10);
        var action = component.get("c.getForecastActuals");
        action.setParams({
            "recordId":recordId,
            "queryStartDate": queryStartDate,
            "queryStopDate": queryStopDate
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                var forecasts = component.get("v.forecasts");
                console.log("Length of forcast from callback: " + forecasts.length)
                //clear array of previous data
                forecasts = []; 
                //load array with new data
                forecasts.push(response.getReturnValue());
                console.log("Length of forcast from callback after push: " + forecasts.length)
                component.set("v.forecasts", forecasts);
                //console.log("Forecast List: " + JSON.stringify(forecasts));
            }

        });
        //Invoke the action
        $A.enqueueAction(action);
    }
})

Best Answer

Push pushes an element on to the Array. An Array may contain another Array, so you've basically made something like this:

[ { Forecast1 }, [ { Forecast2, Forecast3, ... } ] ]

In other words, you now have an Array inside an Array.

Instead, if you want to add items from a list, you should use concat:

forecasts = forecasts.concat(response.getReturnValue());

Note that concat returns a new Array that contains both of the original arrays, hence the assignment back into the forecasts variable.

Related Topic