@Testtest132

Сортировка/фильтрация в Backbone?

Представим, что вы заполнили коллекцию моделями и отрендили. Все отображается в на странице, и пользователь захотел все записи вывести в обратном порядке( или, допустим, только те, которые содержат какое-то ключевое слово)
Как лучше поступить в такой ситуации?
На ум приходи вариант сортировать/фильтровать коллекцию и потом все снова в DOM.
Кто как делает?
  • Вопрос задан
  • 3128 просмотров
Решения вопроса 1
aen
@aen
Keep calm and 'use strict';
Вы все верно предложили. Чаще всего только так и можно сделать. Главное в DOM вставлять сразу всю отрендеренную коллекцию, а не по одной вьюшке. И не забывать подчищать за собой в случае, если есть какие то лихие биндинги.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@xaseros
Я считаю что полностью заново рендерить коллекцию при сортировке это вообще шаг назад от идеологии MVC. рендерить заново надо только то что изменилось.

При сортировке или фильтрации, мы можем использовать умное обновление коллекций с сервера. Оно будет вызывать соответствующие события add, remove, change. На любой списочный интерфейс я завожу 4 "класса", например: CommentListViewClass, CommentItemViewClass, CommentCollectionClass, CommentModelClass.

CommentCollection передаем в CommentListView, и вызываем CommentCollection.fetch()
Собственно вся соль делается в CommentListView, его и прифожу.
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);
        }
    });


При добавлении новой модели в коллекцию, мы инициализируем новый вид элемента списка, передавая ему эту же модель. Это делает метод render_item.

var item = new CommentsItemViewClass({
                model: model,
                templateData: this.templateData
            });
            //получим DOM-элемент вида
            var itemEl = item.render();


Далее у каждого DOM-элемента (this.el) созданного вида добавляется класс (или любой другой атрибут) с cid той модели которую он отображает (это нужно сделать в шаблоне элемента). Затем нужно определить индекс (позицию) модели в коллекции, и разместить этот элемент под элементом вида предыдущей модели в коллекции (ну или воткнуть на самый верх если таковой не найден), этим далее и занимается метод placeItem .

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);
            }


Аналогично при полном обновлении коллекции после sync, только пробежаться надо по всем моделям коллекции, дабы расставить все элементы по местам. Это уже resortItems.

this.collection.each(_.bind(function(m,i){
                var viewEl = this.$("."+m.cid);
                this.placeItem(viewEl, m);
            }, this));
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы