Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
250 views
in Technique[技术] by (71.8m points)

javascript - correctly implement backbone comparators

I'm getting a bit stuck implemented a backbone comparator, I basically want to select different sorting methods based on the route and use the comparator to sort the collection. Ideally I want to keep the sorting logic encapsulated within the collection but seem to be getting stuck. For example

    Requests = Backbone.Collection.extend({
        model : Request,
        comparator : function(ab) {
            return -ab.id;
        },          
        nooffers : function() {
            return this.sortBy(function(ab) {               
                 return ab.get('offers');
            });
        }
    }); 

So by default it sorts based on the default comparator - but in my routing I wish to be able to resort e.g. do something like

   routes : {
        "" : "index",
        '/ordering/:order' : 'ordering'
    },
    ordering : function(theorder) {
        ordering = theorder;
        if(theorder == 'nooffers') {
            Request.comparator = Request.nooffers();
        }
        Request.sort();
        listView.render();  
        howitworksView.render();
    }

However in that case I get an error ('c.call is not a function') any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have a few things wrong here.

This doesn't do what you think it does:

if(theorder == 'nooffers') {
    Request.comparator = Request.nooffers();
}

That executes the nooffers method and assigns its result to Request.comparator. But sortBy returns the sorted list:

nooffers : function() {
    return this.sortBy(function(ab) {               
        return ab.get('offers');
    });
}

and setting that list as the comparator function doesn't do anything useful.

You want to change the assignment to use the function rather that its return value:

if(theorder == 'nooffers') {
    Request.comparator = Request.nooffers;
}

and change the function to be a valid comparator function:

nooffers : function(ab) {
    return ab.get('offers');
}

Demo (run with your console open): http://jsfiddle.net/ambiguous/AAZCa/

But having someone from the outside fiddling with the collection's methods like that smells bad and you shouldn't do it. Instead, you should ask the collection to change its ordering with something like this:

var Requests = Backbone.Collection.extend({
    model: Request,
    comparator: function(ab) {
        if(this._order_by == 'offers')
            return ab.get('offers');
        else if(this._order_by == 'id')
            return -ab.id;
        //...
    },
    order_by_offers: function() {
        this._order_by = 'offers';
        this.sort();
    },
    order_by_default: function() {
        this._order_by = 'id';
        this.sort();
    },
    _order_by: 'id'
});
//...
rs.order_by_offers();

Demo: http://jsfiddle.net/ambiguous/uM9av/

Or you could let the collection swap its own comparator to avoid all the conditional logic inside the comparator:

var Requests = Backbone.Collection.extend({
    model: Request,
    initialize: function() {
        this._order_by_id = this.comparator;
    },
    comparator: function(ab) {
        return -ab.id;
    },
    order_by_offers: function() {
        this.comparator = this._order_by_offers;
        this.sort();
    },
    order_by_default: function() {
        this.comparator = this._order_by_id;
        this.sort();
    },
    _order_by_offers: function(ab) {
        return ab.get('offers');
    }
});

Demo: http://jsfiddle.net/ambiguous/Pjfq2/


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...