简体   繁体   中英

Observe when any Ember.ObjectController in Ember.ArrayController changes

I'm trying to set up mass-action checkboxes (for something like Delete Selected Items) in an Ember App. The idea is to make a mass-action dropdown show or hide if any one of the checkboxes are selected. I haven't put in the dropdown yet since I can't figure out how to observe all elements in the array. How can I:

  1. Set up the Array controller so it observes all client objects
  2. Get the number of checked items when it changes
  3. ALSO: Am I on track with the conventions of how I'm approaching the client itemController?

app/templates/clients.hbs

<section id="clients">
    <h4>my clients</h4>
    <ul>
    {{#each itemController="clients/client"}}
        <li>
            {{input type="checkbox" name="markedForDeletion" checked=markedForDeletion}}
            {{#link-to 'clients.show' this}}
                {{clientName}}
            {{/link-to}}
        </li>
    {{/each}}

    </ul>
</section>
{{#link-to 'clients.new'}}Add client{{/link-to}}
{{outlet}}

router.js

import Ember from 'ember';
import config from './config/environment';

var Router = Ember.Router.extend({
  location: config.locationType
});

export default Router.map(function() {
  this.resource('clients', function() {
    this.route('show', {path: '/:client_id'});
    this.route('new');
  });
});

app/routes/clients.js

import Ember from 'ember';
export default Ember.Route.extend({
    model: function() {
        return this.store.find('client');
    }
});

app/models/client.js

import DS from 'ember-data';
export default DS.Model.extend({
  clientName: DS.attr('string'),
  clientEmail: DS.attr('string')
});

app/controllers/clients.js

import Ember from 'ember';
export default Ember.ArrayController.extend({
    checkBoxesChanged: function() {
    // This fires only once, when the /clients/ route is activated
    console.log('markedForDeletion in array changed');
  }.observes('@each.clients')
});

app/controllers/clients/client.js

import Ember from 'ember';
export default Ember.ObjectController.extend({
    markedForDeletion: true,
    markedForDeletionChanged: function(){
        // This fires correctly
        console.log('markedForDeletion object changed');
    }.observes('markedForDeletion')
});

Edit: Similar question asked here , but I'm afraid the answers didn't help me all that much.

There are a couple of solutions to this. Since your solution only requires the need for an extra property of being checked, I think that an ObjectProxy will meet your needs. If, however, you needed more functionality, then a component would be a better fit.

Note: Before we dive into the solution, though, it's important to note that ArrayController, ObjectController, and ItemController are all being deprecated.

Since we won't be using itemController, you can remove app/controllers/clients/client.js

app/templates/clients.hbs

<section id="clients">
    <h4>my clients</h4>
    <ul>
    {{#each clientsWithMarker as |client|}}
        <li>
            {{input type="checkbox" name="markedForDeletion" checked=client.markedForDeletion}}
            {{#link-to 'clients.show' client}}
                {{client.clientName}}
            {{/link-to}}
        </li>
    {{/each}}

    </ul>
</section>
{{#link-to 'clients.new'}}Add client{{/link-to}}
{{outlet}}

app/controllers/clients.js

import Ember from 'ember';
export default Ember.Controller.extend({
    clientsWithMarker: Ember.computed.map('model', function(client) {
        return Ember.ObjectProxy.create({
            content: client,
            checked: false
        });
    }),

    // This computed property returns an array of ObjectProxies that
    // are checked. It is recalculated automatically
    checkedClients: Ember.computed.filterBy('clientsWithMarker', 'checked', true),

    checkBoxesChanged: function() {
    // This fires only once, when the /clients/ route is activated
    console.log('markedForDeletion in array changed');
  }.observes('clientsWithMarker.@each.checked')
});

This should work, but I haven't actually tested this specific code.

Here is the working example of Multi-Select Checkbox functionality implementation in ember.

http://alexdiliberto.com/posts/ember-toggle-all-checkbox/

http://emberjs.jsbin.com/coliwiwa/5/edit?html,css,js,output

Basically when looping through each item in array, the itemController sends reference of itself to parentController and parentController maintains these references in an array. Here isChecked property is defined inside each itemController instead of attaching to array members. We are using this approach in our production code.

Alternative approach could be to use ObjectProxy and attach isChecked property on each array item of new array, and observe it.

eg. If colors is array then

var newColors = colors.map(function(color){
 return Ember.ObjectProxy.create({
   isChecked: false, 
   content: color
   } 
)};

This way we have create newColors array with isChecked property which we can loop over and we haven't touched the individual items.

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