Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js collection comparator sort by multiple fields?

  this.col = Backbone.Collection.extend({     model: M,     comparator: function(item) {       return item.get("level");     }   }); 

This above code sorts items by level. I want to sort by level, then by title. Can I do that? Thanks.

like image 348
Harry Avatar asked Jan 19 '12 05:01

Harry


2 Answers

@amchang87's answer definitely works, but another that I found worked is simply returning an array of the sortable fields:

this.col = Backbone.Collection.extend({     model: M,     comparator: function(item) {       return [item.get("level"), item.get("title")]     } }); 

I haven't tested this in multiple browsers yet as I think it relies on JS' behavior in sort order for arrays (based on their contents). It definitely works in WebKit.

like image 157
Bo Jeanes Avatar answered Sep 22 '22 21:09

Bo Jeanes


String concatenation works fine when sorting multiple fields in ascending order, but it didn't work for me because 1) I had to support asc/desc per field and 2) certain fields were number field (i.e., I want 10 to come after 2 if it is ascending). So, below was a comparator function I used and worked OK for my needs. It assumes the backbone collection has a variable assigned with 'sortConfig', which is an array of JSON objects with field name and sort order direction. For example,

{     "sort" : [         {             "field": "strField",             "order": "asc"          },          {              "field": "numField",              "order": "desc"          },          ...      ] } 

With the JSON object above assigned as 'sortConfig' to the collection, the function below will make Backbone sort by strField in ascending order first, then sort by numField in descending order, etc. If no sort order is specified, it sorts ascending by default.

multiFieldComparator: function(one, another) {     // 'this' here is Backbone Collection     if (this.sortConfig) {         for (var i = 0; i < this.sortConfig.length; i++) {             if (one.get(this.sortConfig[i].field) > another.get(this.sortConfig[i].field)) {                 return ("desc" != this.sortConfig[i].order) ? 1 : -1;             } else if (one.get(this.sortConfig[i].field) == another.get(this.sortConfig[i].field)) {                 // do nothing but let the loop move further for next layer comparison             } else {                 return ("desc" != this.sortConfig[i].order) ? -1 : 1;             }         }     }     // if we exited out of loop without prematurely returning, the 2 items being     // compared are identical in terms of sortConfig, so return 0     // Or, if it didn't get into the if block due to no 'sortConfig', return 0     // and let the original order not change.     return 0; } 
like image 38
hyong Avatar answered Sep 26 '22 21:09

hyong