1
votes
var stooges = [
     {name: 'moe', age: 40}, 
     {name: 'larry', age: 50}, 
     {name: 'curly', age: 60}
];

_.max(stooges, function(stooge){ return stooge.age; });

=> {name: 'curly', age: 60};

So curly is returned because he is the oldest, he is the max age of the above collection.

P.S (Age might not be the best example) Lets say somehow magically, larry has some kind of disease where he ages 12 years for every year and becomes 62 while curly only turns 61, how do I detect this change?

In my real app the max value in the collection will change periodically and I would like to have a function that detects a change so I can add stuff to notify the user a change in the max has been made.

I know backbone.js has changed, _previousAttributes, and other methods but they seem to only return the actual max value and not the previous max value.

Edit: I have a method in my backbone code to get get the max

getMax : function(attribute) {
    var home = $('#main').attr('data-home'),
        away = $('#main').attr('data-away')
    return this.collection.max(function (player) {
        return player.get("teamName") === home || player.get("teamName") === away? player.get(attribute) : 0;
    }, this);
}

So if I want to get the maximum attribute in my collection I would call this.getMax("points"); and use that to determine who is my max point leader.

I am not sure how to compare an old value to a changed value, ex. "kevin" has 12 points while "adam" has 10, "kevin" is the current max points, so on click I add 3 points to adam he now has "13" points and is now the leader while "kevin" is the previous leader.

So I cannot figure out how to create a method or statement to detect if there is a change in max value

Edit: change handler

// 1 for one point
if(e.keyCode == 49 && !e.ctrlKey || e.keyCode == 97 && !e.ctrlKey) { 
    if(this.$el.hasClass('hover')) {
        var addMake = parseInt(this.model.get('made_one')) + 1;
        var addOnePoint = parseInt(this.model.get('points')) + 1;         
        this.model.save({made_one: addMake, points: addOnePoint});
        feedCollection.create({
            feedItem: 'made a freethrow', 
            playerName: this.model.get('playerName'), 
            teamName: this.model.get('teamName'),
            facebookID: this.model.get('facebookID')
        });
    }
}

Okay so the actual event that changes the model is inside a separate view, it's actually a keypress event. I listen to any changes to the collection inside my statistics view which is the view that handles the max values. Inside the statistics view I render it every time there is a change, so if the values do change it automatically puts the appropriate max value, but I am unsure how to detect that change this.listenTo(this.collection, "change", this.render);.

2
You will need to call _.max again in the change handler (and compare to the previous result) - you can only find larry's disease by testing them every new year. - Bergi
So if I have an event that adds the attribute to the model I would check each time if the previous result changes, how do I capture the old val, I tried storing it in a variable but to no success, could you provide a simple example, easy points. - Michael Joseph Aubry
Can you show us how you tried it? - Bergi
Sure I added some additional info in my post above, basically I have a method that gets the max in my collection, and I am passing it into my template. I render the template when there is a "change" in the collection. - Michael Joseph Aubry
Could you please also show that change event handler (where you call this.getMax("points"), render the template and tried to compare the previous values)? - Bergi

2 Answers

1
votes

You will need to create a sort function for the collection

class People extends Backbone.Collection
  comparator: (p1, p2) ->
    if p1.get("age") > p2.get("age") then -1 else 1

var stooges = 
     {name: 'moe', age: 40}
     {name: 'larry', age: 50}
     {name: 'curly', age: 60}

people = new People(stooges)

# whenever age changes, the people's order will be changed accordingly
people.on "change", people.sort, people

# so people.at(0) will always be the biggest
# people.at(1) will be the last biggest

# keep a reference to highest
highest = people.at(0)

# whenever sort happened, go and check if the highest is changed
people.on "sort", ->
  current_highest = people.at(0)
  create_new_feed(highest) unless current_highest.cid is highest.cid

create_new_feed = (person)->
  feeds.create({name: person.get("name")})
0
votes

Okay so after studying how to use the hasChanged method, I decided to re-configure some code to allow me to simply use that method.

It only returns the attributes that are changed not the whole model, so if I am adding points to a model all I get in return is the points value, and that's no good.

So I created a new collection specifically for all the leaders/max and I simply check if currentPoints changes like below.

leadersCollection.each(function(model) {
    model.save({currentPoints: this.getMaxPointsPlayer().get('playerName')});
    if (model.hasChanged('currentPoints')) {

        //Here I add onto my apps feed, which adds a new item notifying the 
        //user there is a new leader
        feedCollection.create({
            feedItem: 'new leader', 
            playerName: model.get('currentPoints')
        });

    }
}, this);