I'm using a master view with a subview with it's own subview, and I am losing the event on the sub-sub view.
Looking in SO, it looks like a delegateEvents is needed, but I can't figure out how or where.
Also, it seems really hacky to have to pass tbody: tbodyEl[ "0" ].outerHTML
to my template, but I don't know if it's related to the event issue.
Any help greatly appreciated.
mainView:
return Backbone.View.extend({
el: "#content",
initialize: function () {
this.render();
},
render: function () {
var todosView = new TodosView({
collection: projectCol
});
}
});
todosView:
return Backbone.View.extend({
el: "#content-body",
template: _.template([
'<div class="table-responsive">',
'<table id="todo-table" class="table">',
'<span class="caption">Top <%= project %> Tasks <a id="<%= project %>" class="projectName">(See All)</span></a>',
'<thead>',
'<tr>',
'<th>Task</th>',
'<th>Due</th>',
'</tr>',
'</thead>',
'<%= tbody %>',
'</table>',
'</div>'
].join("")),
initialize: function () {
this.render();
},
render: function () {
var projectName = this.collection.models[0].attributes.project;
var tbodyEl = $("<tbody />");
this.collection.each(function (item) {
var todoView = new TodoView({
model: item
});
tbodyEl.append(todoView.el);
});
this.$el.append(this.template({
project: projectName,
tbody: tbodyEl["0"].outerHTML
}));
}
});
todoView:
return Backbone.View.extend({
tagName: "tr",
className: "todo-rec",
template: _.template([
"<td>",
"<label id='task' class='edit'><%= task %></label>",
"<input id='edited-task' class='new-edit' style='display:none;' value='<%= task %>'>",
"</td>",
"<td>",
"<span id='due' class='edit'><%= due %></span>",
"<input id='edited-due' class='new-edit' style='display:none;' value='<%= due %>'>",
"</td>",
].join("")),
events: {
"click .edit": "editFields"
},
initialize: function () {
this.render();
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
editFields: function () {
console.log("todoView: editFields clicked"); // <-- does not fire
}
});
25 Oct Updated: Thanks to @WinterSoldier, this is what I ended up with: code build elements complete before inserting into DOM, and todoView.events works, giving full access to this.model, plus, it looks more 'Backbone-ish':
// mainView:
return Backbone.View.extend( {
el: "#content",
initialize: function(){
this.render();
},
render: function(){
$( "#content-body" ).empty();
var section = new TodosView( { collection: projectCol } ); // should be returning a section div
$( "#content-body" ).append( section.el );
}
} );
// todosView:
return Backbone.View.extend( {
// used tagName so the element can be built complete before inserting into DOM
tagName: "div",
className: "table-responsive",
// tbody changed to empty element
template: _.template( [
'<table id="todo-table" class="table">',
'<span class="caption">Top <%= project %> Tasks <a id="<%= project %>" class="projectName">(See All)</span></a>',
'<thead>',
'<tr>',
'<th>Comp.</th>',
'<th>Task</th>',
'<th>Due</th>',
'<th>Priority</th>',
'<th>Delegated To</th>',
'<th>Project</th>',
'<th>Del.</th>',
'</tr>',
'</thead>',
'<tbody id="tbodyContent"></tbody>',
'</table>' ].join( "" )
),
initialize: function(){
this.render();
},
render: function(){
// new: render the template first, then append rows in #tbody
var projectName = this.collection.models[ 0 ].attributes.project;
this.$el.empty().html( this.template( {
project: projectName
} ) );
var this2 = this;
this.collection.each( function( item ){
var todoView = new TodoView( {model: item} );
this2.$el.find( "#tbodyContent" ).append( todoView.el );
} );
// now returning a <div class="table-responsive" with all rows
return this;
}
} );
// todoView:
// Note: nothing changed from original code
return Backbone.View.extend( {
tagName: "tr",
className: "todo-rec",
template: _.template( [
"<td>",
"<label id='task' class='edit'><%= task %></label>",
"<input id='edited-task' class='new-edit' style='display:none;' value='<%= task %>'>",
"</td>",
"<td>",
"<span id='due' class='edit'><%= due %></span>",
"<input id='edited-due' class='new-edit' style='display:none;' value='<%= due %>'>",
"</td>",
].join( "" )
),
events: {
"click .edit": "editFields"
},
initialize: function() {
this.render();
},
render: function() {
this.$el.html( this.template( this.model.toJSON() ) );
return this;
},
editFields: function() {
console.log( "todoView: editFields clicked", this );
}
} );