Reputation: 4978
I'm trying to figure out how to build a small app consisting of a list where you can select multiple items and toggle to select all/none and see the number of currently selected rows.
I believe that the "selected" state should not be part of the model objects, but I cannot really figure out how to do it.
This is my current setup (which doesn't work obviously yet)
Runnable code http://jsfiddle.net/jacobk/rU35G/1/
var App = Ember.Application.create();
App.ApplicationRoute = Ember.Route.extend({
model: function() { return Ember.A(["Foo", "Bar", "Baz"]); }
});
App.ApplicationController = Ember.ArrayController.extend({
allSelected: false,
selectedCount: function() {
return 0;
}.property()
});
App.RowController = Ember.ObjectController.extend({
isSelected: false
});
<script type="text/x-handlebars" data-template-name="application">
<h3>{{ selectedCount }} rows selected.</h3>
<label>
{{view Ember.Checkbox checkedBinding="allSelected"}}
Toggle select all
</label>
<hr/>
<ul>
{{#each controller itemController="row"}}
<li {{bindAttr class="isSelected"}}>
{{view Ember.Checkbox checkedBinding="isSelected"}} {{this.content}}
</li>
{{/each}}
</ul>
</script>
I'm trying to understand when to use bindings, observers, properties, "needs" etc. and when its appropriate to use controllers vs views and so on. I've yet to grok the general flow of information/data in ember apps.
e.g. should the ArrayController from my example above iterate over the "contained" views/controllers and change the "selected" state when the "select all" check box is toggled OR should all the "sub controllers" observe/"have bindings to" the ArrayController and change themselves when it changes, and if so, how should I propagate data the opposite direction. How would the ArrayController get "all currently selected" rows?
I would love to see the "canonical solution" for this.
Upvotes: 4
Views: 1981
Reputation: 4391
I agree about keeping the selected state out of the model. You need to define the itemController
in the Ember.ArrayController.
here is a working example. http://jsbin.com/sunat/3/edit
App.RowController = Ember.ObjectController.extend({
isSelected: false
});
App.IndexController = Ember.ArrayController.extend({
itemController: 'row',
selectAll: function(key, value) {
if (arguments.length == 2) {
this.setEach('isSelected', value);
return value;
} else {
return this.isEvery('isSelected', true);
}
}.property('@each.isSelected')
});
#template
<script type="text/x-handlebars" id="index" >
<label>
{{input type="checkbox" checked=selectAll}}
Toggle select all
</label>
<hr/>
<ul>
{{#each}}
<li>
{{input type="checkbox" checked=isSelected}} {{name}}
</li>
{{/each}}
</ul>
</script>
Upvotes: 0
Reputation: 111
No need of row controller. @each, computed property and checkedbinding can be utilized to solve this as shown below. isSelected has to be defined in content of the arraycontroller:
App.ApplicationController = Ember.ArrayController.extend({
allSelected: function(key, value) {
if ( value !== undefined ) {
// when check box is ticked, this gets executed
this.setEach( 'isSelected', value );
return value;
} else {
//as a computed property
return !!this.get( 'length' ) &&
this.everyProperty( 'isSelected', true );
}
}.property('@each.isSelected')
selectedCount: function() {
return 0;
}.property()
});
Upvotes: 1