I can successfully do this:
App.SomeCollection = Backbone.Collection.extend({
comparator: function( collection ){
return( collection.get( 'lastName' ) );
}
});
Which is nice if I want to have a collection that is only sorted by 'lastName'. But I need to have this sorting done dynamically. Sometimes, I'll need to sort by, say, 'firstName' instead.
My utter failures include:
I tried passing an extra variable specifying the variable to sort()
on. That did not work. I also tried sortBy()
, which did not work either. I tried passing my own function to sort(), but this did not work either. Passing a user-defined function to sortBy()
only to have the result not have an each
method, defeating the point of having a newly sorted backbone collection.
Can someone provide a practical example of sorting by a variable that is not hard coded into the comparator function? Or any hack you have that works? If not, a working sortBy()
call?
So, this was my solution that actually worked.
Then in the view, I have to M-I-C-K-E-Y M-O-U-S-E it like this:
Since Josh Earl was the only one to even attempt a solution and he did lead me in the right direction, I accept his answer. Thanks Josh :)
This is an old question but I recently had a similar need (sort a collection based on criteria to be supplied by a user click event) and thought I'd share my solution for others tackling this issue. Requires no hardcoded model.get('attribute').
I basically used Dave Newton's approach to extending native JavaScript arrays, and tailored it to Backbone:
Note the "overloadParam". Per the documentation, Backbone uses Underscore's "sortBy" if your comparator function has a single param, and a native JS-style sort if it has two params. We need the latter, hence the "overloadParam".
Interesting question. I would try a variant on the strategy pattern here. You could create a hash of sorting functions, then set
comparator
based on the selected member of the hash:Then you could change your sorting strategy on the fly by updating the value of the
selectedStrategy
property.EDIT: I realized after I went to bed :) that this wouldn't quite work as I wrote it above, because we're passing an object literal to
Collection.extend
. Thecomparator
property will be evaluated once, when the object is created, so it won't change on the fly unless forced to do so. There is probably a cleaner way to do this, but this demonstrates switching the comparator functions on the fly:Here's a jsFiddle that demonstrates this.
The root of all of your problems, I think, is that properties on JavaScript object literals are evaluated immediately when the object is created, so you have to overwrite the property if you want to change it. If you try to write some kind of switching into the property itself it'll get set to an initial value and stay there.
Here's a good blog post that discusses this in a slightly different context.
Change to comparator function by assigning a new function to it and call sort.
This is what I ended up doing for the app I'm currently working on. In my collection I have:
Now I can add few different methods to my collection: fooSort(), barSort(), and bazSort().
I want fooSort to be the default so I set that in my state model like so:
Now all I have to do is write a function in my view that updates the value of "comparatorMethod" depending upon what the user clicks. I set the collection to listen to those changes and do sort(), and I set the view to listen for sort events and do render().
BAZINGA!!!!
Looking at the source code, it seems there's a simple way to do it, setting comparator to string instead of function. This works, given Backbone.Collection mycollection: