Reputation: 147
Hi I'm learning backbone and I am having trouble with binding events to views. My problem is that I have a view constructor that when called, binds all views to a button press event that is only part of one view. I would like the button press event to be bound to only the 1 view that contains the button.
http://jsbin.com/tunazatu/6/edit?js,console,output
So I've looked at the code from this post mutliple event firing which shows that you can have multiple views that have the same el thru tagName but map events only to their html elements. This is also what is done in the localtodos example from Jérôme Gravel-Niquet
I have also tried not declaring el /tunazatu/7/edit?js,console,output but then it seems like no event gets bound.
var AppView = Backbone.View.extend({
tagName:"div", //tagName defined
getName:function(){
console.log(this.model.get('name'));
},
initialize:function(options){
this.listenTo(this.model, 'change', this.render);
var temp_mapper = {appView1:'#route1',appView2:'#route2',appView3:'#route3'};
var m_name = this.model.get('name');
this.template = _.template($(temp_mapper[m_name]).html()); //choose the correct template
},
render:function(){
var temp = this.template(this.model.toJSON()); //populate the template with model data
var newElement = this.$el.html(temp); //put it in the view's tagName
$('#content').html(newElement);
},
events:{
"click button":"log"
},
log:function(){
this.getName();
}
});
Upvotes: 1
Views: 3202
Reputation: 434805
Your problem is that your AppView
really looks like this:
var AppView = Backbone.View.extend({
el: "#content",
//...
Every time you create a new AppView
, you bind another event delegator to #content
but you never remove those delegations. If you create three AppView
s, you end up with three views listening to click button
inside #content
.
I would recommend two things:
View#remove
) as needed. Views should be lightweight enough that putting them together and tearing them down should be cheap.el
. Instead, let each view create its own el
and then let the caller put that el
inside some container.If you do both of those things then your problem will go away. Your AppView
would look more like this:
var AppView = Backbone.View.extend({
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this; // Common practise, you'll see why shortly.
},
// As you already have things...
});
Then your router methods would look more like this:
view1: function() {
if(this.appView)
this.appView.remove();
this.appView = this.createView('appView1');
$('#content').html(this.appView.render().el);
// that `return this` is handy ----------^^
},
If you must stick with your current approach then you'll have to call undelegateEvents
on the current AppView
before you render another one and delegateEvents
on the new AppView
after you render it.
But really, don't be afraid to destroy views that you don't need right at this moment: destroy any view that you don't need on the page right now and create new instances when you need them. There are cases where you don't want to destroy your views but you can usually avoid it.
Upvotes: 1