@Praveen, yes, this is totally normal. Here is what is happening:
When we say that the body attribute is defined on all components we mean that it's defined on the base <aura:component/>
from which all components inherit. Here is a simplified version.
<aura:component/>
<aura:attribute name="body" type="Aura.Component[]"/>
{!v.body}
</aura:component>
As you can see, the base component outputs the body tag that it receives in its own body, otherwise, nothing would be rendered. Angular calls that process "transclusion", the inclusion of content from another context.
When you write this:
<aura:component>
<div>Body part</div>
<ui:button label="Push Me" press="{!c.printCmpBody}"/>
</aura:component>
You are setting the body tag of the parent component. Everything defined in your component is the "lexical definition", and it's passed to its parent. If you want to read it, you could use cmp.getSuper().get("v.body")
but it's a deprecated API, and it will probably not work. However, that's the idea behind it.
Why is it working like this? Let's call your component c:myComponent
and use it inside an app:
<c:myComponent>
<i>Instance Part</i>
</c:myComponent>
This is equivalent to this format:
<c:myComponent>
<aura:set attribute="body>
<i>Hello</i>
</aura:set>
<c:myComponent>
As you see, every component needs to receive an attribute body independently of what it defines internally. You can try this format, it does work, but it's unnecessary except to illustrate how to set the body of a component.
Now, your component can ignore its body attribute as in your original code, or it can use it like this:
<aura:component>
<div>Body part</div>
{!v.body}
<ui:button label="Push Me" press="{!c.printCmpBody}"/>
</aura:component>
You can place the expression {!v.body}
anywhere you want.
The rendered content will then be equal to the instance's v.body
plus the component-defined lexical definition:
v.body = <i>Instance Part</i>
+
lexical scope = <div>Body part</div>{!v.body}...
=
Rendered: <div>Body part</div><i>Instance Part</i>...
You can get more information on how the attribute body works by looking at slides 24, 25, and 27:
Mastering the Lightning Framework - Part 1
And the explications are at around 15:00 minute here:
Mastering the Lightning Framework - Part 1
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
Best Answer
You will have to assign the accList back to the aura:attribute after pushing elements.