In Ember.js how to notify an ArrayController's corresponding itemController, when a property on the ArrayController changes

StackOverflow https://stackoverflow.com/questions/23146300

  •  05-07-2023
  •  | 
  •  

Pergunta

I have an EmailsController (ArrayController), which stores all the emails. I have an EmailController (ObjectController) that has a parameter that stores if the actual Email is selected or not. I am trying to implement a button in the emails template, that selects or deselects all the Emails. So somehow I need to notify the EmailController via an action of the EmailsController and change the EmailController's isChecked parameter.

I am trying to use the itemController, the needs, and the controllerBinding parameters, but nothing works.

Here are the controllers:

App.EmailsController = Ember.ArrayController.extend({
    needs: ["Email"],
    itemController: 'Email',
    checkAll: true,
    actions: {
        checkAllEmails: function() {
            this.toggleProperty("checkAll");
            console.log(this.get("checkAll"));
        } 
    }
});


App.EmailController = Ember.ObjectController.extend({
    needs: ["Emails"],
    controllerBinding: 'controllers.Emails',
    isChecked: true,
    checkAllChanged: function() {
        //this should execute, but currently it does not
        this.set("isChecked",this.get('controller.checkAll'));
    }.property("controller")
});

Here is the corresponding jsFiddle: http://jsfiddle.net/JqZK2/4/ The goal would be to toggle the selection of the checkboxes via the Check All button.

Thanks!

Foi útil?

Solução

Your mixing a few different mechanisms and your using a few wrong conventions. It's not always easy to find this stuff though, so don't fret.

Referencing Controllers

Even though controllers are created with an Uppercase format, the are stored in the lowercase format and your needs property should be:

needs: ['emails'],

You then access other controllers through the controllers property:

this.get('controllers.emails.checkAll')

Computed Properties

Computed properties can be used as a getter/setter for a variable and also as a way to alias other properties. For example, if you wanted the isChecked property on the Email controller to be directly linked to the value of the checkAll property of the Emails controller, you could do this:

isChecked: function() {
  return this.get('controllers.emails.checkAll');
}.property('controllers.emails.checkAll')

Although computed properties can do much more, this basic form is really just a computed alias, and there is a utility function to make it easier:

isChecked: Ember.computed.alias('controllers.emails.checkAll')

Observables

An observable basically creates a method that will be called when the value it observes changes. A computed alias would cause all items to uncheck or check whenever you clicked on any one of them, since their isChecked property is linked directly to the checkAll property of the parent controller. Instead of your checkAllChanged method identifying as a property it should use observes:

checkAllChanged: function() {
  this.set("isChecked",this.get('controllers.emails.checkAll'));
}.observes("controllers.emails.checkAll")

This way when the checkAll property changes on the parent controller, this method updates the isChecked properties of all items to its value, but if you uncheck or check an individual item, it doesn't affect the other items.

Bindings

Bindings are somewhat deprecated; from reading issues on the Ember github repository I believe the creators of Ember seem to favor using computed properties, aliases, and observables instead. That is not to say they don't work and if your goal was to avoid having to type out controllers.emails every time, you could create one like you did (I wouldn't call it controller though, cause thats really quite ambiguous):

emailsBinding: 'controllers.emails'

Using a computed alias instead:

emails: Ember.computed.alias('controllers.emails')

You could then change your observer to:

checkAllChanged: function() {
  this.set("isChecked",this.get('emails.checkAll'));
}.observes("emails.checkAll")

Heres an updated version of your jsFiddle: http://jsfiddle.net/tMuQn/

Outras dicas

You could just iterate through the emails, changing their properties from the parent controller. You don't need to specify needs or observe a variable.

App.EmailsController = Ember.ArrayController.extend({
    itemController: 'email',
    actions: {
      checkAllEmails: function() {
        this.forEach(function(email) {
          email.toggleProperty("isChecked");
        });
      } 
    }
});

Also, you typically don't set initial values like you did with isChecked = true; I believe that's creating a static shared property on the prototype (not what you intended). Instead, set the property on init, or pass it in from your original json data.

See the code: http://jsfiddle.net/JqZK2/5/

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top