Ember.js: вычислить сумму свойства всех дочерних моделей

Мое приложение имеет следующие модели:

App.Store = DS.Store.extend({
    revision: 11,
    adapter: 'DS.FixtureAdapter'
});

App.List = DS.Model.extend({
    name: DS.attr('string'),
    users: DS.hasMany('App.User'),
    tweetsUnread: function(){
        /////////////////////////////////////////
        // Code to dynamically calculate the sum 
        // of tweetsUnread property of all
        // App.User that are related to this list
        /////////////////////////////////////////
    }
});

App.User = DS.Model.extend({
    screenName: DS.attr('string'),
    tweets: DS.hasMany('App.Tweet'),
    tweetsUnread: function(){
        // TODO: check if this is the correct way to do it
        return this.get('tweets').get('length');
    }.property('[email protected]'),
    list: DS.belongsTo('App.List')
});

App.Tweet = DS.Model.extend({
    text: DS.attr('string'),
    user: DS.belongsTo('App.User')
});

Как я могу вычислить сумму всего файла App.User.tweetsUnread и автоматически обновить файл App.List.tweetsUnread?

Ответы

Ответ 1

Следующее должно сделать это. Может быть более сжатое решение, использующее сокращение, но я никогда не использовал его сам: -)

App.List = DS.Model.extend({
    name: DS.attr('string'),
    users: DS.hasMany('App.User'),
    tweetsUnread: function(){
        var users = this.get("users");
        var ret = 0;
        users.forEach(function(user){
            ret += users.get("tweetsUnread");
        });
        return ret;
    }.property("[email protected]")
});

Обновление: Это более элегантное решение, использующее сокращение. Я никогда не использовал его, и это не проверено, но я уверен, что это должно работать:

App.List = DS.Model.extend({
    name: DS.attr('string'),
    users: DS.hasMany('App.User'),
    tweetsUnread: function(){
        var users = this.get("users");
        return users.reduce(0, function(previousValue, user){
            return previousValue + users.get("tweetsUnread");
        });
    }.property("[email protected]")
});

В Ember 1.1 API для уменьшения изменился! спасибо @joelcox для подсказки, что параметры initialValue и callback изменили свое положение. Итак, вот верная версия кода:

App.List = DS.Model.extend({
    name: DS.attr('string'),
    users: DS.hasMany('App.User'),
    tweetsUnread: function(){
        var users = this.get("users");
        return users.reduce(function(previousValue, user){
            return previousValue + user.get("tweetsUnread");
        }, 0);
    }.property("[email protected]")
});

Ответ 2

Другим вариантом было бы использовать Ember.computed.sum см. здесь

App.List = DS.Model.extend({
  name: DS.attr('string'),
  users: DS.hasMany('App.User'),

  tweetsUnread: Ember.computed.mapBy('users', 'tweetsUnread'),
  totalTweetsUnread: Ember.computed.sum('tweetsUnread')   
});

Ответ 3

При использовании coffeescript мне нравится использовать однострочный синтаксис, сначала получая массив значений свойств с .mapBy('propertyName'), а затем используя простой файл coffeescript reduce:

@get('users').mapBy('tweetsUnread').reduce (a, b) -> a + b