I have a question, really basic stuff I think but:
I've only seen examples with a collection view and single view dependent on a collection being updated. What if you have multiple views trying to subscribe to a collections events, ie reset, addOne, addAll etc...
Am I missing some point about doing/not doing this? Do you have any examples of this? Does that even make sense?
Any info is MUCH appreciated
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});
BackboneJS - Collection. Collections are ordered sets of Models. We just need to extend the backbone's collection class to create our own collection. Any event that is triggered on a model in a collection will also be triggered on the collection directly. This allows you to listen for changes to specific attributes in any model in a collection.
Backbone views can be thought of as: Observers that keep listening to the DOM events and in case the event fires, taking the appropriate actions. Objects backed by models that are responsible for rendering the model data on the screen. Let us see how we can use backbone.js views to efficiently manage the applications.
The Backbone object itself mixes in Events, and can be used to emit any global events that your application needs. "add" (model, collection, options) — when a model is added to a collection. "remove" (model, collection, options) — when a model is removed from a collection.
We just need to extend the backbone's collection class to create our own collection. Any event that is triggered on a model in a collection will also be triggered on the collection directly. This allows you to listen for changes to specific attributes in any model in a collection.
What you're doing is perfectly fine and part of the reason for using Backbone. From the Backbone introduction:
Whenever a UI action causes an attribute of a model to change, the model triggers a "change" event; all the Views that display the model's state can be notified of the change,
Note that they say "all the Views", not "the view".
One example of multiple views for a single collection would be a chat system. Suppose you have a collection of users that are online; then you might have one simple view in the header that displays the number of people that are online and another view (of the same collection) that lists the users:
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;
}
});
Then you'd have one OnlineUsers
instance but both your CounterView
and ListView
instances would be watching it. When people come online or go offline, both views will be updated as desired.
Simple demo: http://jsfiddle.net/ambiguous/eX7gZ/
The above example situation sounds like exactly the sort of thing you're doing and it is exactly the sort of thing that Backbone is for. Good job.
We had the same problem. We needed to use multiple jQuery Templates with unique internal events for each model without using multiple holder views. This is the solution that we came up with:
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...
});
}
});
Full source and working example: http://jsfiddle.net/HLv5z/9/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With