T
T
Testtest1322015-01-23 15:40:50
JavaScript
Testtest132, 2015-01-23 15:40:50

Sorting/filtering in Backbone?

Let's imagine that you populated a collection with models and rendered it. Everything is displayed on the page, and the user wanted to display all the records in reverse order (or, let's say, only those that contain some keyword)
What is the best way to deal with this situation?
The option to sort / filter the collection comes to mind and then everything is back in the DOM.
Who does what?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
aen, 2015-01-23
@Testtest132

All of you suggested correctly. Most of the time, that's the only way to do it. The main thing in the DOM is to insert the entire rendered collection at once, and not one view at a time. And do not forget to clean up after yourself if there are any dashing bindings.

X
xaseros, 2015-05-13
@xaseros

I believe that completely re-rendering a collection when sorting is generally a step back from the MVC ideology. You only need to re-render what has changed.
When sorting or filtering, we can use smart updating of collections from the server. It will trigger the appropriate add, remove, change events. I add 4 "classes" to any list interface, for example: CommentListViewClass, CommentItemViewClass, CommentCollectionClass, CommentModelClass.
We pass CommentCollection to CommentListView, and call CommentCollection.fetch()
Actually, all the salt is done in CommentListView, I will fetch it.

var CommentsListViewClass = Backbone.View.extend({
        initialize: function(options){
            this.templateData = options && options.templateData || {};
            this.listenTo(this.collection, "add", this.renderItem);
            this.listenTo(this.collection, "add remove sync", this.renderUpdate);
            this.listenTo(this.collection, "sync", this.resortItems);
            
            this.itemViews = [];
        },
        render: function(){
            this.$el.empty();
        },
        renderUpdate: function(){
            $('.comments_count').html(this.collection.length);
        },
        resortItems: function(){
            this.collection.each(_.bind(function(m,i){
                var viewEl = this.$("."+m.cid);
                this.placeItem(viewEl, m);
            }, this));
        },
        placeItem: function(itemEl, model){
            var index = _.indexOf(this.collection.models, model);
            //console.log(index, itemEl,model);
            if(index == 0){
                console.log("#"+ index ,model.id, 'ontop');
                this.$el.prepend(itemEl);
            } else {
                var pIndex = index-1;
                var cid = this.collection.models[pIndex].cid;
                this.$el.find('.'+cid).after(itemEl);
                console.log("#"+ index, model.id, "after " + this.collection.models[pIndex].id );
            }
        },
        renderItem: function(model, collection, options){
            var item = new CommentsItemViewClass({
                model: model,
                templateData: this.templateData
            });
            
            var itemEl = item.render();
            this.placeItem(itemEl, model);
        }
    });

When adding a new model to the collection, we initialize a new kind of list element by passing it the same model. This is what the render_item method does .
var item = new CommentsItemViewClass({
                model: model,
                templateData: this.templateData
            });
            //получим DOM-элемент вида
            var itemEl = item.render();

Next, for each DOM element (this.el) of the created view, a class (or any other attribute) is added with the cid of the model that it displays (this must be done in the element template). Then you need to determine the index (position) of the model in the collection, and place this element under the view element of the previous model in the collection (well, or stick it to the very top if one is not found), this is what the placeItem method does next.
var index = _.indexOf(this.collection.models, model);
            //console.log(index, itemEl,model);
            if(index == 0){
                this.$el.prepend(itemEl);
            } else {
                var pIndex = index-1;
                //cid предыдущей модели
                var cid = this.collection.models[pIndex].cid;
                this.$el.find('.'+cid).after(itemEl);
            }

Similarly, when a collection is completely updated after sync, it is only necessary to go over all the models of the collection in order to put all the elements in their places. This is already resortItems.
this.collection.each(_.bind(function(m,i){
                var viewEl = this.$("."+m.cid);
                this.placeItem(viewEl, m);
            }, this));

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question