javascriptbackbone.jsrequirejsbackbone-routing

How to render a view from a route?


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;
    }
});

Solution

  • Underscore's _.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());
    

    Backbone view rendering

    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:

    Default route

    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: