custom comparator #219
Comments
Each cell in my grid can be a string, JSON object, or array, so I definitely needed a custom comparator - I ran into similar issues and ended up just having to modify the _makeComparator function in backbone-pageable.js. Probably not the "right" way to do it, but it worked for me... I'd love to hear solutions from others who've done a custom comparator. |
@gbedardsice has asked a similar question recently: backbone-paginator/backbone-pageable#89 This seems to be a recurring issue for a couple of people of late. Suggestions on how to improve this is welcomed. |
This may be a bit off topic, but I simply want case insensitive column sorting. I would prefer to have "comparator : function(a,b){...}" as a column option, but any hints on how to do this without modifying backgrid would be appreciated. |
The problem I see with passing a custom |
What about passing |
How about this? columns: [
name: "name",
label: "Name",
// Put your custom logic that returns a comparator function based on the direction here
// Similar to Backbone.PagableCollection#_makeComparator
comparatorProvider: function (attr, order) {
return function (left, right) {
// no-op
if (order == null) return 0;
var l = left.get(attr), r = right.get(attr), t;
// if descending order, swap left and right
if (order === 1) t = l, l = r, r = t;
// compare as usual
if (l === r) return 0;
else if (l < r) return -1;
return 1;
}
}
] This should help folks who are dealing with nested data who only have Formatters to use to display them but not sort them. |
This could work, but why would this logic (the swapping of left and right) ever change? Why not have it built in inside |
Are you thinking of a function that lets you extract the values from the models? |
What do you think of something like that? Keep in mind this is not tested at all, just a quick mockup. |
The only ambiguity I see with this is that the |
Also see this commit: backbone-paginator/backbone-pageable@02a0819 |
I'm thinking along similar lines. I think most people will only have trouble with this line: var l = left.get(attr), r = right.get(attr), t; That's pretty much the only line they'll have to customize, the rest should be the same for everyone. How about just a value extractor that you can provide to the column definition? BTW, that commit you just posted looks like it's coming from backbone-pageable's repo, how did you do that? |
Are you talking about something like this? var l = left.get(this.column.modelAttribute()), r = right.get(this.column.modelAttribute())
The same way you linked to the backbone-pageable issue, except you replace the issue number ( |
Why is it a problem to supply a simple, classic comparator function?
|
@gbedardsice Something like this: columns: [
name: "name",
label: "Name",
value: function (model, attr) {
return model.get(attr).b.c[3];
}
] The value will be used as the left and right values for the comparator generated automagically by HeaderCell. If not supplied, the function (model, attr) {
return model.get(attr);
} |
So everywhere that |
No. Only when extracting the attribute value for sorting. You already have formatters that you can override to process nested data. |
@wyuenho I'm starting to like your idea of defining the sort value/attr in the column/cell def. I was trying to pass that into the comparator factory. I took the approach of extending the HeaderCell with a custom comparator, in my case was for Ignore Case + Nulls Last. So it started looking like... var IgnoreCaseHeaderCell = Backgrid.HeaderCell.extend({
sort: function(columnName, direction){
return Backgrid.HeaderCell.prototype.sort.call(this, columnName, direction, ignoreCaseSortMaker(columnName, direction));
}
}); and the ignoreCase factory started looking like: var ignoreCaseSortMaker = function(attr, direction) {
return function (a, b) {
var left = a.get(attr);
var right = b.get(attr);
var order;
if (direction === "ascending") order = -1;
else if (direction === "descending") order = 1;
else order = null;
// no-op
//if (order === null) return 0;
if (_.isUndefined(left)) { return 1; }
else if (_.isUndefined(right)) { return 1; }
var l = left[0], r = right[0], t;
// if descending order, swap left and right
if (order === 1) t = l, l = r, r = t;
if (l === r) return 0;
if (_.isString(l)) {
l = l.toLowerCase();
r = r.toLowerCase();
}
return l < r ? -1 : 1;
};
}; i'm not sure the logic is working correctly here. but the issue i see is the sort doesn't kick in until the 3rd header sort click, or when direction is removed...and then it blows up. And the 1st and 2nd header sort clicks are hitting the default comparators instead. With sort methods being defined in multiple places (header and pageable extensions) it's challenging to hit on a single fix for this. and of course i set the respective header in the col def depending on cell type. sort of like: ...
{"name": blah,
"label": blah,
"cell": blah_type,
"headerCell": (blah_type === "string" ? IgnoreCaseHeaderCell : Backgrid.HeaderCell),
"editable": blah || false
}, ... |
@wyuenho Ok I see what you mean. Makes sense. Also, concerning the |
I know I know I have a fix for this and the sortable: "somestring" in a few days. Feel free to send over a PR if you are impatient. |
Yes, this seems perfect. var comparator = function(left, right) {
var l = left.toLowerCase(), r = right.toLowerCase();
if(l === r) return 0;
if(l < r) return -1;
return 1;
};
cell = new Backgrid.HeaderCell({
collection: words,
column: {
name: "name",
cell: "string",
comparator: comparator
}
}); |
Reopening until I'm done moving things around... |
How can we find out what library or libraries need to be updated in order to utilize the new sorting changes? I updated just backbone-pageable.js and now the paginator links are broken. When I click on a page other than page 1, it moves to the page, but the 1 remains highlighted. I'm not sure if there's something else I need to do/update or if it's a bug.. |
@mparisi76 According to #231 this issue is fixed if you update to the latest paginator extension from master. Ping me on #231 if it doesn't work out for you. I'll release 0.3 this week. Will document an upgrade path. |
@wyuenho I just started using Backgrid, and need to exclude group-headings while sorting. Please help. Regards, |
Question: what would be the canonical approach to implementing a custom sort comparator for PageableCollections in Client mode? Looking to use an ignoreCase sorting fn for strings. Tried overriding the comparator in the collection def, but it seems to fallback to native or _cid sorting. Tried to extend the HeaderCell view and pass in a new comparator def there, but not yet successful. What would be your approach? Many thanks!
The text was updated successfully, but these errors were encountered: