简体   繁体   中英

How to create a multiselect list in Ember.js

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>
  • Should the individual "row items" be controlled using a custom view per row, or a custom controller like in the fiddle above
  • How to propagate the "select all" from the ArrayController to all the individual controllers (or views if that's a better fit)

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.

eg 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.

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()
    });

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM