5

We are migrating over to Lightning Web Components in the last couple of weeks now and we had some struggles with the arrays in Javascript. On a trackable array, when I call push in a wiredMethod, Array.push won't update the view. We found a workaround but I was wondering if there is a more elegant solution to this. Please take a look at the code snippets:

import { LightningElement, wire, track } from 'lwc';
import getData from '@salesforce/apex/LWCController.getData';

export default class myLWComponent extends LightningElement {
    @track error;
    @track dataArray = [];
    @track processedArray = [];

    @wire(getData)
    wiredMethod({ error, data }) {
        if (data) {
            this.dataArray = data.arr;
            this.dataArray.forEach(function (value) {
                // do some work on data here
                this.processedArray.push(value);
            }
        } else if (error) {
            this.error = error;
        }
    }                 
}

And on the view here:

<lightning-card title="Card Title">
    <template for:each={processedArray} for:item='item'>
        {item.title}
    </template>
</lightning-card>

Here is our workaround:

export default class myLWComponent extends LightningElement {
    @track error;
    @track dataArray = [];
    @track processedArray = [];

    @wire(getData)
    wiredMethod({ error, data }) {
        if (data) {
            this.dataArray = data.arr;
            let tempArray = [];
            this.dataArray.forEach(function (value) {
                // do some work on data here
                this.tempArray.push(value);
            }
            this.processedArray = tempArray;
        } else if (error) {
            this.error = error;
        }
    }                 
}

As you can see from the work around, if we set array to the temp array, framework understands that the array is updated and updates the view accordingly. We also tried setting values as follows which didn't work:

this.processedArray[index] = value;

We are wondering why push doesn't work and/or if there is a better way to do this.

  • 1
    All the operations on tracked arrays including Array.prototype.push are observed (developer.salesforce.com/docs/component-library/tools/…). Are you able to reproduce the same issue on the playground? – pmdartus Mar 8 '19 at 8:18
  • @pmdartus I am able to reproduce this exact scenario in the playground using lightning-accordion with the multiple-js example. If you add a simple lightning button to the page: <lightning-button label="Open-B" title="Open B" onclick={handleClick} class="slds-m-left_x-small"></lightning-button> And add the handler for that button: handleClick(event) { this.activeSections.push('B'); } Then you will see that clicking on the button does not open 'B' in addition to 'A' and 'C'. I was unable to find any workaround in this scenario. – DaveS Jun 4 '19 at 8:44
  • @pmdartus I've added a similar question on lightning-accordion array.push() which has reproducible Playground code. salesforce.stackexchange.com/questions/264664/… – DaveS Jun 4 '19 at 9:25
4

If you rebuild the array as below and reassign, the @track sees the change:

this.myArray = [...this.myArray, myNewElement];

My guess is that the @track isn't noticing the original push() in the array since an array is actually only a pointer. When items are added to an array, it will never change the pointer, thus @track sees no change.

However, in my workaround above, a brand new array is created which will change the pointer. @track sees the new pointer and refreshes accordingly.

  • 1
    This is what we ended up doing. I will mark this one as the answer. Thank you! – Selçuk Jun 10 '19 at 23:37
  • 1
    Please don't do this workarounds since it will hurt performance. Let's always try to understand why something doesn't work. @track should work as expected. – Diego yesterday
  • 1
    Here is an example of how push is working just fine: developer.salesforce.com/docs/component-library/tools/… – Diego yesterday

Not the answer you're looking for? Browse other questions tagged or ask your own question.