With a lack of documentation I'm trying to understand how data binding works under locker service, when using different types in <aura:attribute type="...">
to pass values between parent & child components.
Before locker everything worked beautifully, I was able to pass complex type into child component, manipulate it there an still have the same instance in the parent object, which for me enabled nice capabilities of code structuring and decomposition.
Now I know that "Secure Object" proxy is introduced. I've seen numerous questions asked here related to this, but I'd really appreciate if someone can answer what is a bug, and what will be working in target solution.
Below I tried to describe 4 scenarios and my observations. What I did are two simple components - parent and child. Parent has one attribute, passed to child. Child component has input field that allow to modify this attribute. This is how it looks:
Test 1 - Strings
For Strings, everything seems to work fine. Console.log
displays proper value for both parent & child components. Binding seems to be done live. When you type in value in child component inputText
, it's displayed live in the parent component output: Parent: {!v.testAtr}
Parent Component
<aura:component>
<aura:attribute name="testAtr" type="String" access="global"/>
Parent: {!v.testAtr} <a onclick="{!c.logTestAtr}">LOG PARENT</a>
<br></br><br></br>
<c:childCmp testAtr="{!v.testAtr}"/>
</aura:component>
Parent Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr"));
}
Child Component
<aura:component>
<aura:attribute name="testAtr" type="String" access="global"/>
child: <ui:inputText value="{!v.testAtr}"/>
<a onclick="{!c.logTestAtr}">LOG CHILD</a>
</aura:component>
Child Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr"));
}
Test 2 - Maps (with default value)
For Maps, when you specify default value for data attribute - almost all works exactly like for strings, but the data binding in the parent component is not actualized when you change value in child component. So in child inputText you have 'test', when you change it to 'test2' console.log from parent will show you 'test2', but output: Parent: {!v.testAtr}
will still show old 'test' value.
Parent Component
<aura:component>
<aura:attribute name="testAtr" type="Map" default="'data': 'test'" access="global"/>
Parent: {!v.testAtr.data} <a onclick="{!c.logTestAtr}">LOG PARENT</a>
<br></br><br></br>
<c:childCmp testAtr="{!v.testAtr}"/>
</aura:component>
Parent Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr").data);
}
Child Component
<aura:component>
<aura:attribute name="testAtr" type="Map" access="global"/>
child: <ui:inputText value="{!v.testAtr.data}"/>
<a onclick="{!c.logTestAtr}">LOG CHILD</a>
</aura:component>
Child Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr").data);
}
Test 3 - Maps (without setting default value)
Now, what happens if you don't specify default="'data': 'test'"
in the parent attribute, just default="{}"
to avoid null pointer? Console.log from both parent & child are showing undefined
, even after putting the value into inputText.
Parent Component
<aura:component>
<aura:attribute name="testAtr" type="Map" default="{}" access="global"/>
Parent: {!v.testAtr.data} <a onclick="{!c.logTestAtr}">LOG PARENT</a>
<br></br><br></br>
<c:childCmp testAtr="{!v.testAtr}"/>
</aura:component>
Parent Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr").data);
}
Child Component
<aura:component>
<aura:attribute name="testAtr" type="Map" access="global"/>
child: <ui:inputText value="{!v.testAtr.data}"/>
<a onclick="{!c.logTestAtr}">LOG CHILD</a>
</aura:component>
Child Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr").data);
}
Test 4 - Objects
Now - the same case as Test 2 - but we use type="Object"
now. I would expect simillar behavior as Map, but here - I get undefined
all the times in console.log
Parent Component
<aura:component>
<aura:attribute name="testAtr" type="Object" default="'data': 'test'" access="global"/>
Parent: {!v.testAtr.data} <a onclick="{!c.logTestAtr}">LOG PARENT</a>
<br></br><br></br>
<c:childCmp testAtr="{!v.testAtr}"/>
</aura:component>
Parent Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr").data);
}
Child Component
<aura:component>
<aura:attribute name="testAtr" type="Object" access="global"/>
child: <ui:inputText value="{!v.testAtr.data}"/>
<a onclick="{!c.logTestAtr}">LOG CHILD</a>
</aura:component>
Child Component Controller:
logTestAtr : function(component) {
console.log(component.get("v.testAtr").data);
}
I'd appreciate if somebody can comment on this, or at least direct me to some further reading.
Thank you.