My application has the following models:
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('tweets.@each'),
list: DS.belongsTo('App.List')
});
App.Tweet = DS.Model.extend({
text: DS.attr('string'),
user: DS.belongsTo('App.User')
});
How can I calculate the sum of all App.User.tweetsUnread and make it automatically update App.List.tweetsUnread?
Another option would be to use Ember.computed.sum
see here
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')
});
The following should do it. There might be an more concise solution using reduce, but i have never used it myself :-)
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]")
});
Update: This is a more elegant solution using reduce. I have never used it and this isn't tested but i am quite confident that this should work:
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]")
});
In Ember 1.1 the API for reduce has changed! Thx @joelcox for the hint, that the parameters initialValue and callback have changed their position. So here the correct version of the code:
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]")
});
When using coffeescript, I like to use the one-line syntax, first getting the property values array with .mapBy('propertyName')
and then using a simple coffeescript reduce
:
@get('users').mapBy('tweetsUnread').reduce (a, b) -> a + b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With