samedi 16 janvier 2016

Ember Set/Save Doesn't Update Computed Properties

I'm working on a simple budgeting app with 2 models: Category and Entries. Categories have many entries.

Ember 2.2

Problem: Categories have computed properties total and difference that watch associated entries. These computed properties update when entries are added and removed, but not when entry attributes change.

Here is the Category model:

# app/models/category.js
export default DS.Model.extend({
  name:          DS.attr('string'),
  budgetAmount:  DS.attr('number'),
  budgetSheet:   DS.belongsTo('budget-sheet'),
  entries:       DS.hasMany('entry'),

  total: Ember.computed('entries.@each.amount', {
    get() {
      let entries = this.get('entries');

      return entries.reduce(function(previousValue, entry){
        return previousValue + entry.get('amount');
      }, 0);
    }
  }),

  difference: Ember.computed('budgetAmount', 'total', {
    get() {
      return this.get('budgetAmount') - this.get('total');
    }
  })
});

Here is the route:

# app/routes/budget-sheet.js
export default Ember.Route.extend(AuthenticatedRouteMixin, {
  model(params) {
    return this.store.find('budget-sheet', params.budgetSheetId);
  },

  setupController(controller, model) {
    controller.set('budgetSheet', model);
    controller.set('categories', model.get('categories'));
  }
});

Here is the controller with the actions to add/remove/update entries:

# app/controllers/budget-sheet.js
export default Ember.Controller.extend({

  entries: Ember.computed('categories.@each.entries', {
    get() {
      let result = [];

      this.get('categories').map(function(category) {
        category.get('entries').forEach(function(entry) {
          return result.push(entry);
        });
      });

      return result;
    }
  }),

  actions: {
    ...

    updateEntry(id, attribute, value) {
      let entry = this.store.peekRecord('entry', id);
      entry.set(attribute, value);
      entry.save();
    },

    deleteEntry(id) {
      let entry = this.store.peekRecord('entry', id);
      entry.destroyRecord();
    }
  }
});

The template iterates through categories and displays the computed properties. The template also has an entry-form component that is responsible for sending data to the functions in the controller (addEntry, updateEntry).

When an entry is added or removed, the template is updated. When an entry's category is changed, the template is updated. When an entry's amount is updated, the template does not update.




Aucun commentaire:

Enregistrer un commentaire