Reputation: 3368
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.
Upvotes: 1
Views: 411
Reputation: 378
I agree with the solution from Lux but if you want to try something else, maybe on your child component you could add a computed property that checks the name or default to another string. This allow you to have different default values on the different child templates (assuming you have different child components that use the same name
property).
child-component.js
export default Ember.Component.extend({
child_name: Ember.computed('name', function() {
return this.get('name') || 'tom';
}),
});
child-component.hbs
{{child_name}}
<br>
{{surname}}
Upvotes: 0
Reputation: 18240
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.
Upvotes: 3