Backbone.js - Правильный способ фильтрации и отображения данных коллекции в представлении
У меня есть огромный список задач, загруженных с самого начала.
Я хочу показать их в зависимости от выбранного списка/входящих, чтобы не было дополнительных нагрузок для каждого списка.
window.Task = Backbone.Model.extend({});
window.TasksCollection = Backbone.Collection.extend({
model: Task,
url: '/api/tasks',
inbox: function() {
return this.filter(function(task) {
return task.get('list') == null;
});
},
list: function(id) {
return this.filter(function(task) {
return task.get('list') == id;
});
}
});
window.tasks = new TasksCollection;
window.TaskView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#item-template').html()),
initialize: function() {
_.bindAll(this, 'render', 'close');
this.model.bind('change', this.render);
this.model.view = this;
},
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
this.setContent();
return this;
},
});
window.TasksView = Backbone.View.extend({
el: '#todo-list',
collection: tasks,
initialize: function() {
_.bindAll(this, 'render');
this.collection.bind('reset', this.render);
this.collection.fetch();
},
render: function() {
var t = this;
$(t.el).html('');
this.collection.each(function(task) {
var view = new TaskView({ model:task });
$(t.el).append( view.render().el );
});
return this;
},
});
window.Nicetask = Backbone.Router.extend({
routes: {
'': 'inbox',
'/inbox': 'inbox',
'/list/:id': 'list',
},
initialize: function() {
_.bindAll(this, 'inbox', 'list');
window.tasksView = new TasksView;
},
inbox: function() {
tasks.reset( tasks.inbox() );
},
list: function(id) {
tasks.reset( tasks.list(id) );
}
});
Этот код работает, но функция reset()
удаляет другие задачи из фактического списка из коллекции задач. А на другом маршруте сбор задач пуст.
Есть ли разумный способ достичь этого? спасибо за любую идею.
ps: начинающий новичок
UPDATE
спасибо to @sled и @ibjhb для комментариев, вот фрагмент рабочего решения.
window.TasksView = Backbone.View.extend({
el: '#todo-list',
collection: Backbone.Collection.extend(),
initialize: function() {
_.bindAll(this, 'render', 'addOne', 'addAll');
this.collection.bind('add', this.addOne);
this.collection.bind('reset', this.render);
},
render: function(data) {
$(this.el).html('');
_.each(data, function(task) {
this.addOne(task);
}, this);
return this;
},
addOne: function(task) {
var view = new TaskView({ model:task });
$(this.el).append( view.render().el );
},
});
window.Nicetask = Backbone.Router.extend({
routes: {
'': 'inbox',
'/inbox': 'inbox',
'/today': 'today',
'/list/:id': 'list',
},
initialize: function() {
_.bindAll(this, 'inbox', 'today');
window.tasksView = new TasksView;
window.menuView = new MenuListView;
tasks.fetch();
},
inbox: function() {
tasksView.render( tasks.inbox() );
},
today: function() {
tasksView.render( tasks.today() );
},
list: function(id) {
tasksView.render( tasks.list(id) );
}
});
Ответы
Ответ 1
Думаю, вам нужно использовать другую коллекцию. Например, в вашем почтовом ящике сделайте следующее:
inbox: function(){
currentCollection = new TasksCollection(tasks.inbox());
}
Я не тестировал это, но когда вы делаете .reset(); вы удаляете все свои модели и загружаете те, которые были переданы.
Ответ 2
@sled там опечатки в коде, который вы опубликовали, см. комментарии в строке. Вы размещали это как проект где-то?
// add models
add: function(models, options) {
// TYPO: next line was missing, so single models not handled.
models = _.isArray(models) ? models.slice() : [models];
var self = this;
models = _.filter(models, this.filter);
// return if no models exist
// TYPO: returned undefined, so was not chainable
if(models.length == 0) { return this; }
// actually add the models to the superset
this.superset.add(models, options);
return this;
},
// remove models
remove: function(models, options) {
// TYPO: next line was missing, so single models not handled.
models = _.isArray(models) ? models.slice() : [models];
// remove model from superset
this.superset.remove(_.filter(_.filter(models, function(cm) {
// TYPO: not 'm != null', causes error to be thrown
return cm != null;
}), this.filter), options);
// TYPO: missing return so not chainable
return this;
},
Ответ 3
одно быстрое изменение к вам, вы используете
$(this.el).html('');
Мое понимание ваших взглядов и связанных привязок событий будет по-прежнему существовать в памяти браузера, поэтому вам идеально нужно использовать view.remove() в TaskView, чтобы правильно очистить привязки событий, а также html.
Это немного другое отношение к ответу, поскольку я искал решение подобной проблемы, надеюсь, что это может помочь другим.
Моя проблема: - для фильтрации полной коллекции по атрибутам модели. например. пользователь нажимает на представление модели, получает список (некоторых) атрибутов, выбирая атрибут, фильтрует коллекцию, чтобы показывать только те, у которых одинаковое значение.
Маршрут, который я беру, - это вызов метода в коллекции из представления, в моем случае представление специфично для модели, поэтому:
this.model.collection.myFilter(attr,val);
где attr - атрибут модели, связанной с коллекцией, тогда в фильтре что-то вроде
myFilter: function(attr, val){
var groupByAttr = this.groupBy(function(article){
var res = (val === undefined)? true : (article.get(attr) == val);
article.set({selected:res});
return res;
});
return groupByAttr;
}
Я использовал ._ groupBy, так как это возвращает 2 массива (положительный/отрицательный), которые могут быть полезны. Установив атрибут режима "selected" и привязав его к представлению модели, я могу легко переключить класс, который отображает или скрывает представление.
if (val === undefined) добавляется как простой способ очистки фильтра, вызывая тот же метод без значения.