0
votes

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('[email protected]', {
    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('[email protected]', {
    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.

3
I don't know, what ember-version you are on, but have you tried: total: Ember.computed('entries.[].amount', ? - Remi Smirra
Thanks for the recommendation. I'm on Ember 2.2. I did try updating the computed properties to the entries.[].amount, but that didn't fix the issue of the properties not updating. - jeffreyj

3 Answers

0
votes

It turns out that there is a bug around computed properties in Ember 2.1.1 and 2.2.0 as described by this issue: https://github.com/emberjs/ember.js/issues/12475

A comment in the Github issue recommended manually setting {async: false} on the hasMany relationship, which worked for my problem. This change corrected all issues that I was having with computed properties not updating:

# app/models/category.js
  - entries: DS.hasMany('entry'),
  + entries: DS.hasMany('entry', {async: false}),
0
votes

You did run into this open Bug that @jeffreyj linked.

But you could just work around that by replacing

total: Ember.computed('[email protected]', {

with

total: Ember.computed('[email protected]', {

This is because entries will return a PromiseArray and there is @each currently broken. But unter the content you have the actual value, so this will work.

-1
votes

In Ember 2.2 @each is no longer present, although you don“t get any error using it the result of object.@each is always an empty array

if you only want to get I would personally use a property function

EDIT: This is wrong for properties [email protected] is still correct link to deprecation guide in answers