I am trying to assign default values for one of my components at init
lifecycle hook; in case an undefined value is passed from parent component. Initially everything seems to be working as expected; however when my component is forced a re-render (possibly via another property value update at parent component); undefined value at parent component is written back to my component.
This means; the value assignment I made during initialization is not reflected to parent component, in other words two-way-binding is temporarily not working (the values of parent and child components are not synchronized). Is it the expected behavior or am I missing sth. important about init event? Where is the appropriate place to initialize undefined values of a component? See the twiddle for a simple illustration.
Okay, first a way to work around is to use the update
function on the attr
. Checkout this twiddle.
I replaced this.set('name', 'tom')
with this.attrs.name.update('tom')
in the .js
and {{name}}
with {{attrs.name}}
in the .hbs
.
Another way to work around is just to wrap the asignment in a Ember.run.later
like I've done here, where I replaced this.set('name', 'tom')
with that:
Ember.run.later(() => {
this.set('name', 'tom');
});
So that are the workarounds.
The fact that the bindings are not completely set up on init has a long history. But generally its an anti pattern to initialize a value in a child component and give this value up to the parent. It makes your code less readable and is agains the DDAU (Data down, Actions up) principle.
I recommend to initialize the data explicit when you create your models, not implicit during your component evaluation cycle.
For default values that you don't want to store I recommend you to write a computed property:
nameWithDefault: computed('name', {
get() {
return get(this, 'name') || 'tom';
},
set(key, val) {
set(this, 'name', val);
}
})
This is explicit, does not write down the data after a component is viewed, and works for the user.