Reputation: 14534
var RowView = Backbone.View.extend({
tagName: 'li',
className: 'course-row',
events: {
"click .table-row": "rowClick" // problem here!
},
initialize: function() {},
template: _.template(tpl),
render: function() {
var rowStr = this.template({course: this.model});
$(this.el).append(rowStr);
},
rowClick: function (e) {
alert(e);
}
});
Above code defines a Backbone Row view. I'd like to create and render several several rows in a table, so I did:
data.forEach(function(rowData){
var row = new RowView({model: course, el: mountPoint});
row.render();
});
If I create 2 rows, the event is bind twice( 2 alert msg if I click on the row), 3 rows 3 times. I avoided this problem by defining the event at parent views, but if I really need attach event handler at each row, how do I avoid the double event biding problem?
Upvotes: 0
Views: 177
Reputation: 434665
You're doing this:
data.forEach(function(rowData){
var row = new RowView({model: course, el: mountPoint});
row.render();
});
That means that your view will ignore its tagName
and className
and just go ahead and bind itself to the el
you supply because:
this.el
can be resolved from a DOM selector string or an Element; otherwise it will be created from the view'stagName
,className
,id
andattributes
properties.
A view's events
are bound to its el
using delegation and you're binding multiple views (which happen to be the same view "class") so of course you're getting multiple event bindings.
If your rows really are supposed to be <li class="course-row">
elements then you want to do a couple things:
Let the RowView
s create and own their own el
s. Keep the tagName
and className
attributes in your RowView
and stop passing the el
to the constructor. You should change $(this.el)
to this.$el
too, there's no need to create another jQuery object when Backbone has already stashed one away for you.
Return this
from RowView
's render
, this is standard practice and makes the next step a bit nicer.
Whatever creates your RowView
s should create them, render
them, and then put them inside a container. You appear to be trying to use mountPoint
(which is presumable a <ul>
) as the container so you want to say:
data.forEach(function(rowData) {
var row = new RowView({model: course});
mountPoint.append(row.render().el);
// This is why (2) above -----^^^
});
That assumes that mountPoint
is a jQuery instance, if that's not the case then you'd want to say $(mountPoint).append(row.render().el)
instead (or do a var $mountPoint = $(mountPoint)
above the forEach
and use $mountPoint.append
inside it).
A personal rule of thumb: if you're passing el
to a view constructor then you're almost certainly making a mistake. If you know exactly why you're passing el
to the constructor, know the consequences, and know how to deal with them then you're adult enough to run with scissors so go right ahead.
Upvotes: 2