[SalesForce] Handler change not working with attribute updated inside aura:iteration

change handler doesn't work when the attribute is a list which can be updated an aura:iteration.

In the following example, we never go to controller method itemsChange ( except at the init) whereas the attribute value is well updated, as you can see in the console when you click on "click me".

Related doc: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/ref_aura_valueChange.htm

Snippet to reproduce with 2 copy/paste :

App :

    <aura:attribute name="SomeList" type="Object[]" />

    <aura:handler name="change" value="{!v.SomeList}" action="    {!c.itemsChange}"/>

    <aura:iteration items="{!v.SomeList}" var="ListItem">
        <c:CmpInputText value="{!ListItem.SomeVal}" />
    </aura:iteration>

    <a onclick="{!c.clickMe}">CLICK ME</a>

</aura:application>

Controller:

({
    doInit : function(component, event, helper) {
        var SomeList = [
            {'SomeVal': 'INITIAL'},
            {'SomeVal': 'VALUES'},
            {'SomeVal': 'HERE'}
        ] ;
        component.set('v.SomeList',SomeList);
        console.debug('INIT VALUES' +     JSON.stringify(component.get('v.SomeList')));
    },

    clickMe : function(component, event, helper) {
        console.debug('AFTER CLICK     '+JSON.stringify(component.get('v.SomeList')));
    } ,

    itemsChange : function(component, event, helper) {
        alert('SomeList has changed');
        console.debug('ONCHANGE :'+     JSON.stringify(component.get('v.SomeList'),null,2));
    }        
})

Best Answer

I was facing a similar issue and I found a workaround for this.

Parent component

<aura:component>
   <aura:attribute name="lstAddresses" type="Address__c[]" access="global"/>
   <aura:handler name="change" value="{!v.lstAddresses}" action="{!c.itemsChange}"/>
   <aura:if isTrue="{!v.showAddAddress}">
         <c:AddEditAddress myObject="{'sobjectType': 'Address__c'}" lstAddresses="{!v.lstAddresses}"  />
      </aura:if>
</aura:component>

Child component

<aura:component>
   <aura:attribute name="lstAddresses" type="Address__c[]" access="global"/>
</aura:component>

Here I have just cut short the code, which is sufficient enough to clear the doubt So Here in the controller js of child component I was adding a address object in the list aura attribute, but the handler for lstAddresses change event was not firing, inshort some how the bidirectional binding was not working as expected

I just updated my code section little bit where I was performing push on the list like this

var lstAddresses = JSON.parse(JSON.stringify(component.get("v.lstAddresses")));
lstAddresses.push(addressObj);
component.set("v.lstAddresses",lstAddresses);

I found that now the change event handler of parent component gets called in init as well as on pushing a new address record from child component. So may be it is the case that in case of collection we have to use this way. Let me know if that worked for you

Related Topic