Reputation: 2486
I have the following backbone.js view shown below. It was working fine, and now the click event does not execute when the form button is clicked. No errors in console, or any other obvious signs of why is shown.
window.FormOptionView = Backbone.View.extend({
template: _.template($('#test-option').html()),
render: function (eventName) {
$('#test1').append(this.template(this.model.toJSON()));
$('#test2').append(this.template(this.model.toJSON()));
return this;
}
});
window.AddTestView = Backbone.View.extend({
template: _.template($('#test-add').html()),
initialize: function () {
this.collection.bind("reset", this.render, this);
this.render();
},
events: {
"click button": "addTest"
},
addTest: function(event){
event.preventDefault();
var test = new Test({
test1: {
firstName: $("#test1 option:selected").val(),
lastName: $("#test1Score").val()
},
test2: {
firstName: $("#test2 option:selected").val(),
lastName: $("#test2Score").val()
}
});
test.add(result);
app.navigate("tests", true);
},
render: function (eventName) {
$('#content').html(this.template());
_.each(this.collection.models, function (test) {
this.renderSelectBox(test);
}, this);
return this;
},
renderSelectBox: function (item) {
var optionView = new FormOptionView({
model: item
});
$(this.el).append(optionView.render().el);
}
});
The corrosponding HTML
<script type="text/template" id="test-option">
<option><%= firstName %> <%= lastName %></option>
</script>
<script type="text/template" id="test-add">
<form id="addTest" action="#">
<label for="test1">Test1:</label>
<select id="test1">
<option></option>
</select>
<label for="test1Score">Score:</label>
<input id="test1Score" type="number" />
<label for="test2">Test 2:</label>
<select id="test2">
<option></option>
</select>
<label for="test2Score">Score:</label>
<input id="test2Score" type="number" />
<button id="add">Add</button>
</form>
</script>
Upvotes: 0
Views: 480
Reputation: 434915
Your problem, as you've already discovered, is that your view wasn't handling its el
properly.
When your view is rendered, Backbone hooks up the events by using jQuery's delegate
on the view's this.el
.
If you don't explicitly set the el
(through the constructor as new V({ el: ... })
, in the view's definition as el: ...
, or by calling setElement
), then the el
will be constructed using various view properties as noted in the documentation; the default el
is just a simple <div>
. This is where your empty <div>
s are coming from.
You were doing this:
render: function (eventName) {
$('#content').html(this.template());
_.each(this.collection.models, function (test) {
this.renderSelectBox(test);
}, this);
return this;
}
and somewhere else you were probably doing a simple add_test_view.render()
. The result is that the event delegate
is bound to the view's el
(an empty <div>
) and that el
is never added to the DOM; if you have delegate
bound to something that isn't in the DOM then you never get any events.
If you say el: '#content'
in your view definition, then Backbone will use #content
as your el
and your view would look more like this:
el: '#content',
//...
render: function (eventName) {
this.$el.html(this.template());
this.collection.each(function(test) {
this.renderSelectBox(test);
}, this);
return this;
},
renderSelectBox: function (item) {
var optionView = new FormOptionView({
model: item
});
this.$el.append(optionView.render().el);
}
Notice that I switch to this.collection.each
, Backbone collections have various Underscore methods mixed in so you don't have to access collection.models
manually; I've also switched to this.$el
since view already have a cached jQuery'd version of this.el
.
Upvotes: 0
Reputation: 2486
Just found the views el
tag corresponded to a bunch of empty <div>
s. Not to sure why but a simple el: $('#content')
managed to fix the problem. Thanks
Upvotes: 0
Reputation: 5133
Without seeing the corresponding HTML, my best guess is that your <button>
is outside the scope of your view. Click events are only attached to children of the root element of your View.
Upvotes: 1