We have looked at computed properties a couple of times now. Today, we are going
to revisit them one final time. We are going to look at the array computed,
@each
, and
filterBy
and
filter
.
We are going to look at these with Ember Twiddle once again. Let's first look at how to watch an array with a computed property. If we have a list of folks:
// inside component/controller
listTeams: [
Ember.Object.create({name: 'Cubs', best: true}),
Ember.Object.create({name: 'Bears', best: false}),
Ember.Object.create({name: 'Bulls', best: false}),
Ember.Object.create({name: 'Blackhawks', best: true})
],
And we want to watch this for changes, let's set up an action to add items to this list:
{{input value=toAddToList}}
<button {{action 'addToList'}}>Add Team To List</button>
actions: {
addToList(){
let newObj = Ember.Object.create({name: this.get('toAddToList')});
this.get('listTeams').addObject(newObj);
this.set('toAddToList', '');
}
}
Now back in our template, let's show the
listTeams
values and the values in a
computed that we will change called
computedListTeams
.
<table>
<tr>
<th>
listTeams:
</th>
<th>
listTeamsComputed:
</th>
</tr>
<tr>
<td>
<ul>
{{#each listTeams as |team|}}
<li>{{team.name}}</li>
{{/each}}
</ul>
</td>
<td>
<ul>
{{#each listTeamsComputed as |team|}}
<li>{{team}}</li>
{{/each}}
</ul>
</td>
</tr>
</table>
<h3>
Now, let's create that computed property. You might write it something like this:
listTeamsComputed: Ember.computed('listTeams', function(){
return this.get('listTeams').map(team => team.name);
}),
But as you can see as we add numbers here, that doesn't work. Why is that? It is because the computed property is watching the property listTeams, but it isn't watching for items being added to or removed from the array. To correct this, we just have to change our computed property just a touch.
listTeamsComputed: Ember.computed('listTeams.[]', function(){
return this.get('listTeams').map(team => team.name);
})
Now we are watching for changes in the array rather than changes in the property. And as you can see it works, so if you need to create a computed property that watches the values of an array, you just add the dot and square brackets and it will work as expected.
Now, let's look at the
@each
for computed. If you have an array of objects and
you want to watch one of the properties on the object you can use the computed
@each
. Let's look at that.
First, let's update our template to iterate over a new computed property and add let's add an action to toggle some property on back in our first each block.
<ul>
{{#each listTeams as |team|}}
<li>
{{team.name}}: {{team.best}}
<button {{action 'toggleOpt' team}}>toggleBest</button>
</li>
{{/each}}
</ul>
...
<ul>
{{#each computedObjArr as |obj|}}
<li>{{obj}}</li>
{{/each}}
</ul>
Now, in the controller, implement our action, then we can add our computed property.
computedObjArr: Ember.computed('listTeams', function(){
return this.get('listTeams').map(obj => obj.get('best'));
}),
actions:{
toggleOpt(obj){
obj.toggleProperty('best');
}
}
First lets look at it just referencing the
listTeams
, obviously, this doesn't
work. Now, if we add the array brackets, it still doesn't work. The brackets are
just watching for adding and removing items from the array, we need to watch if
the properties on the objects in the array change. In this case we need
@each
.
computedObjArr: Ember.computed('listTeams.@smoothterminal.com', function(){
return this.get('objArray').map(obj => obj.get('best'));
})
Now we can see that our computed is working. We can actually make this a little more concise use Ember.computed's mapBy method:
computedObjArr: Ember.computed.mapBy('listTeams', 'best')
We can use most of this code to look at filterBy. Let's just add a computed
property that filters our objects by the
best
property:
computedObjArrBest: Ember.computed.filterBy('listTeams', 'best'),
computedObjArrNotBest: Ember.computed.filterBy('listTeams', 'best', false),
We can also use
Ember.computed.filter()
which takes an object as its first
argument and a callback function as its second argument. The signature of the
callback is item, index, array. So, to get the same result as the best computed
above we could do:
computedObjArrBest: Ember.computed.filter('listTeams.@smoothterminal.com', function(obj){
return obj.get('best');
}),
That's it for today. I'll see you tomorrow when we get will have an exercise and look at some links.
Comments for Once More with Computed Properties