My app contains two views with templates, router, model and collection.
root
js
collections
-collection.js
models
-model.js
routers
-router.js
templates
-add_item.html
-list.html
views
-add_item.js
-list.js
index.html
In router.js
, I'm trying to navigate to a child view.
define([
'jquery',
'backbone',
'views/item'
], function($, Backbone, ItemView) {
'use strict';
return Backbone.Router.extend({
routes: {
'': 'list',
'list/add': 'addItem',
'list/edit/:id': 'editItem'
},
addItem: function() {
new ItemView();
}
});
});
By looking at the call stack, I see that my router triggers. But the template of my child view doesn't initializes.
item.js
code:
return Backbone.View.extend({
template: _.template(itemTemplate),
events: {
'click #save': 'saveItem',
'click #cancel': 'cancel'
},
initialize: function() {
this.render();
},
render: function() {
this.$el.html(this.template);
return this;
}
});
_.template
Underscore
_.template
function takes a template string as argument (and optionally a settings object) and returns a new pre-compiled template function which can take an object as an argument.
template: _.template(itemTemplate), // this returns a function, which is fine here.
This line is fine, but the following one puts the returned function as the HTML content:
this.$el.html(this.template); // a function reference as HTML?!
You need to call the pre-compiled template function to get the string:
this.$el.html(this.template());
Now that the view's default root element (el
) is correctly filled with the template content.
<div>The div element is the default root element, this text is the template</div>
But once the template is rendered, the view's element is still not in the page. To make it part of the page, you could:
put the view's el
manually into another element in the router
addItem: function() {
var view = new ItemView();
$("#content").html(view.render().el);
}
I put view.render()
here because rendering in the initialize
is not my preferred pattern as it's limiting the reuse of the view. But it really depends on what's the view for.
pass a selector string or element to the el
constructor option of the view
new ItemView({ el: '#the-view-element-id' });
create the view with a hard-coded el
property (this can be overridden by the el
option above)
Backbone.View.extend({
el: '#the-view-element-id',
/* ... */
If you want to default to the list
route, you could make the routes
object like this:
routes: {
'list/add': 'addItem',
'list/edit/:id': 'editItem'
// catch-all (default) route at the end
'*anything': 'list',
},
Additional information: