Магистраль: несколько просмотров подписки на одно событие коллекции? Это плохая практика?
У меня есть вопрос, действительно основной материал, который я думаю, но:
Я видел только примеры с представлением коллекции и отдельным представлением, зависящим от обновляемой коллекции. Что делать, если у вас несколько просмотров, пытающихся подписаться на события коллекций, то есть reset, addOne, addAll и т.д.
Я пропустил какой-то момент о том, чтобы делать/не делать этого? У вас есть примеры этого? Это даже имеет смысл?
Любая информация МНОГО оценивается
var Coll = Backbone.Collection.extend({
model: SingleModel,
url: 'service',
initialize: function(){
console.log('collection inited')
}
});
var SingleModel = Backbone.Collection.extend({});
var CollView = Backbone.View.extend({
el: 'ul',
template: Handlebars.compile(someContainerTemplate),
init: function(){
_.bindAll(this, 'render', 'addAll', 'addOne');
this.collection.bind("reset", this.addAll);
this.collection.fetch();
},
render: function(){
$(this.el).append(this.template())
},
addAll: function(){
this.collection.each(this.addOne);
},
addOne: function(model){
var view = new SingleView({ model: model })
}
})
var SingleView = Backbone.View.extend({
tagName: "li",
events: {
"click .delete": "remove"
},
template: Handlebars.compile(someTemplateForSingleItem),
initialize: function() {
_.bindAll(this,'render');
this.model.bind('save', this.addOne);
this.model.bind('destroy', removeEl);
},
remove: function(){
this.model.destroy();
},
removeEl: function(){
$(this.el).remove();
},
render: function() {
var context = this.model.toJSON();
return $(this.el).append(this.template(context));
},
})
// standard so far (excluding any bad practices),
// but what if you have another view dependent on
// say the number of length of the collection, and
// you want it to update if any single models are destroyed
var HeaderView = Backbone.View.extend({
tagName: "div#header",
template: Handlebars.compile(someHeaderTemplate),
initialize: function() {
_.bindAll(this,'render');
this.model.bind('save', this.addOne);
},
render: function() {
//assigning this collection length
var context = this.collection.length;
return $(this.el).append(this.template(context));
},
});
var coll = new Coll();
new CollView({ collection: coll });
new HeaderView({ collection: coll});
Ответы
Ответ 1
То, что вы делаете, прекрасно и часть причины использования Backbone. Из Введение в базовую станцию :
Всякий раз, когда действие пользовательского интерфейса вызывает изменение атрибута модели, модель запускает событие "изменения"; все представления, отображающие состояние модели, могут быть уведомлены об изменении,
Обратите внимание, что они говорят "все представления", а не "вид".
Одним из примеров нескольких представлений для одной коллекции будет чат-система. Предположим, у вас есть коллекция пользователей, которые находятся в сети; то у вас может быть один простой вид в заголовке, который отображает количество людей, которые находятся в сети, и другое представление (из той же коллекции), в котором перечислены пользователи:
var User = Backbone.Model.extend({});
var OnlineUsers = Backbone.Collection.extend({
model: User
});
var CounterView = Backbone.View.extend({
tagName: 'span',
initialize: function() {
_.bindAll(this, 'render');
this.collection.on('add', this.render);
// other interesting events...
},
render: function() {
this.$el.text(this.collection.size());
return this;
}
});
var ListView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render');
this.collection.on('add', this.render);
// other interesting events...
},
render: function() {
var html = this.collection.map(function(m) {
return '<p>' + m.get('name') + '</p>';
});
this.$el.html(html.join(''));
return this;
}
});
Тогда у вас будет один экземпляр OnlineUsers
, но оба экземпляра CounterView
и ListView
будут смотреть его. Когда люди выходят в Интернет или выходят в автономный режим, оба представления будут обновляться по желанию.
Простая демонстрация: http://jsfiddle.net/ambiguous/eX7gZ/
В приведенной выше ситуации ситуация звучит точно так же, как вы делаете, и это именно то, для чего нужна эталон. Хорошая работа.
Ответ 2
У нас была та же проблема. Нам нужно было использовать несколько шаблонов jQuery с уникальными внутренними событиями для каждой модели, не используя несколько видов держателей. Это решение, с которым мы столкнулись:
var myHolderView = Backbone.View.extend({
el: '#views',
render: function(){
// This is because 'this' change inside the collection.each
var $this = this;
// If you want a wrapper template
var wrapperHtml = $('#view-wrapper-template').tmpl();
$this.$el.append(wrapperHtml);
$wrapper = $this.$el.find('> div'); // If wrapper is a div
$this.collection.each(function(model){
// Render and append the viewA with internal events
var viewA = new myViewA({model: model});
viewA.render();
// Use this to add the views content (viewA.el) to this views element ('#views')
//$this.$el.append(viewA.el);
// Use this to add the view content (viewA.el) to this views wrapper element ($wrapper)
$wrapper.append(viewA.el);
// Render and append the viewB with internal events
var viewB = new myViewB({model: model});
viewB.render();
//$this.$el.append(viewB.el);
$wrapper.append(viewB.el);
// Add more views here...
});
}
});
Полный исходный и рабочий пример:
http://jsfiddle.net/HLv5z/9/