I'm trying to sort a Backbone.js collection in reverse order. There are previous replies on how to do this with integers, but none with strings.
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.comparator = function(chapter) {
return chapter.get("title");
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
The above code sorts the chapters from A -> Z, but how do I write a comparator that sorts it from Z -> A?
I just solved a similar problem with table sorting and I wanted to share the code since I didn't find much help in these answers:
in this case I simply set comparator to string instead of a function; the string has to be the name of the property you want to sort by. Then I just call reverse on the models if the order has to be inverse.
As Backbone merely uses the .sortBy method, simply proxy in your own logic:
..or add it somewhere else..
There are two versions of the comparator function that you can use, either the sortBy version - which was shown in the example, which takes one parameter, or sort - which you can return a more standard sort function, which the documentation says:
So in this case, we can write a different comparator function:
So you should get as a response:
If you're working with non-numerical values, there is no obvious way to do a reverse sort. Backbone makes use of the
_.sortBy()
and_.sortedIndex()
methods from Underscore to order the models based on the comparator, and these methods automatically sort in ascending order. The naive way to do this would be to usechapters.pluck('title').reverse()
, as the result ofpluck
will be an array. But callingreverse
on some Collection methods will reverse the Collection models in place, so next time you call it, the models will be back in ascending order. You could always do something like:This would not affect the models array in your Backbone collection, as it would create a completely new results array in memory, but retain references to the original models, so calling things like
save
would still update the Collection state.But that's not very elegant, and creates a lot of extra coding throughout your project any time you want to reverse the results. I think we can do better.
In order to make this work, you'll need to perform a bit of unwieldy JavaScript ninjary in your comparator method to make this work - note this is untested:
This concept probably needs improving to take into account symbols, etc., but essentially it inverts the comparator string in such a way that "Z" becomes "0", "Y" becomes "1", etc., which should produce the reverse sort you're after.
Just add minus before
chapter.get
You could:
0xffff
(the maximum return value ofstring.charCodeAt
),String.fromCharCode
to turn that back into string of "negated" charactersand that will be your sorting key.
And voila:
Note: if your comparison strings are long (as in 65 kb or more), you may run into trouble (see Matt's comment below). To avoid this, and speed up comparisons a bit, just use a shorter slice of your comparison string. (In the above example, you could go for
chapter.get("title").slice(0, 100).split("")
instead.) How long a slice you need will depend on your application.