Rendering jQuery Templates With Backbone Views

In my previous examples of using views with Backbone.js, I showed a simple login form that was built directly in to the page’s html markup. In a more complex app, you are likely going to load content from a server via ajax / json calls and render that out to the browser all within the backbone / jQuery code. jQuery’s template plugin makes it really easy to render content directly in the browser, and combining that with Backbone makes it even easier to manage.

 

Render A Template From A View

There’s a number of different ways to setup an html page so that you can render a template out to it. In this example, I have a div that will display a list of users and a template stuffed into a script block, for jQuery template to use.

<html>
  <head>
    <script src="jquery-1.6.1.min.js"></script> 
    <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
    <script src="underscore-min.js"></script> 
    <script src="backbone-min.js"></script> 
    <script src="example.js"></script>

    <style type="text/css">
      fieldset {
        width: 500px;
      }
      #user-edit ul {
        list-style-type: none;
      }
    </style>

    <script id="user-list-template" type="text/x-jquery-tmpl">
      <li>
        ${firstname} 
        ${lastname} 
      </li>
    </script>
  </head>
  <body>

    <div id="user-list">
      <fieldset>
        <legend>Users</legend>
        <ul></uL>
      </fieldset>
    </div>

  </body>
</html>

The div starts it’s life with a fieldset and an unsorted list, but no data in it. When you load this in your browser, you don’t see anything very interesting or useful:

Screen shot 2011 06 20 at 10 09 12 PM

We need to populate this with some information about our users. To get things rolling, we can hard code a few users as json documents and stuff them into a user collection.

var user1 = new User()
user1.set({firstname: "Derick", lastname: "Bailey", id: 0});
var user2 = new User()
user2.set({firstname: "JoAnn", lastname: "Tsang", id: 1});

var users = new UserList([user1, user2]);

Next, we need a view object that represents the list of users on the screen. We can use backbone’s “el” attribute to identify the “#user-list” element on the view, and we can provide our own “template” attribute that will reference the “#user-list-template” template.

var UserListView = Backbone.View.extend({
    el: $("#user-list ul"),

    render: function(){
      var template = $("#user-list-template");
      var html = template.tmpl(this.model.toJSON());
      this.el.html(html);
    }
});

The ‘el’ attribute points to our currently empty, unordered list within our ‘#user-list’ element. The “render” method is used to do the template rendering with the data that we provide the view – the list of users.

With the view in place, we can put it all together with a call to instantiate the view and pass in the data we have.

var userListView = new UserListView({model: users});
userListView.render();

We’re passing the user list into the user list view with a json document, and an attribute named ‘model’. Backbone recognizes this attribute and assigned the contents of the attribute to ‘this.model’ within the view. The call to ‘userListView.render()’ method then kicks in the jQuery template and reading the json data from this.model, producing a rendered user list and appending it to the inner html of ‘this.el’ – the unordered list in our ‘#user-list’ element.

The end result of this view rendering itself is a list of user names.

Screen shot 2011 06 20 at 10 50 00 PM

 

Side Note On The Render Method

The backbone documentation talks about the render method being a built in method in a backbone view that doesn’t do anything, with it’s default implementation. That’s fine – we may be talking about a template method pattern or something similar in the implementation. However, the presence of this method in the base View, and the documentation for it, are a little confusing to me. I have never seen the render method called for me. In every instance of every view I’ve built with backbone, I have always had to call the render method myself. If i always have to call it myself, why does it even exist on the base View object and why is it documented as a method that the base View knows about?

 

Extracting The Render Method

The render method that we provided in this example is very simple – read the template from the html, render the data from the user list model into it, and append it in to the unordered list. With a small modification, though, we can extract this method into something that is not only simple, but more flexible.

All we need to do is move the ‘template’ variable out of the render method and on to the view definition, directly.

var UserListView = Backbone.View.extend({
    el: $("#user-list ul"),
    template: $("#user-list-template"),

    render: function(){
      var html = this.template.tmpl(this.model.toJSON());
      this.el.html(html);
    }
});

The rendered view is exactly the same. However, we no longer have to re-compile the template every time the view. We also no longer have anything view-specific in our render method. This makes the method a prime candidate for extracting into a base class, for a scenario where you have multiple views on a page – which is highly likely in a real backbone app.

To extract the ‘render’ method, create another view called ‘TemplatedView’. This view will extend the usual ‘Backbone.View’ but will only have 1 method in it – the ‘render’ method.

var TemplatedView = Backbone.View.extend({
    render: function(){
      var html = this.template.tmpl(this.model.toJSON());
      this.el.html(html);
    }
});

var UserListView = TemplatedView.extend({
    el: $("#user-list ul"),
    template: $("#user-list-template"),
});

We also removed the ‘render’ method from the ‘UserListView’ and changed the object that it extends to the new ‘TemplatedView’. The end result is still the same as we previously had – a rendered list of user names. However, we now have the ability to re-use the rendering implementation across multiple views in our backbone page. Additionally, the ‘UserListView’ has been reduced to 2 lines of configuration. This is much more appealing on a number of fronts.

 

Overriding Render Without Losing The Templating

There are going to be times where you want to have a view that is rendered with the same templating mechanism, but has additional needs as well. For example, you may need to render a user edit view and need to attach to a ‘#save’ and ‘#cancel’ button after the view is rendered. In the world of object-oriented languages, you would normally call the super-class’ implementation of the method that you have overridden. The same holds true for javascript, which is an object-oriented language. Unfortunately, javascript makes this a little more verbose than other languages.

var UserEditView = TemplatedView.extend({
    el: $("#user-edit"),
    template: $("#user-edit-template"),

    render: function(){
      TemplatedView.prototype.render.call(this);

      this.save = $("#save");
      this.cancel = $("#cancel");
    }
});

Since javascript uses a prototype-based object inheritance system, we have to reference the prototype that our view inherits from and ‘.call’ the ‘render’ method from there. The ‘call’ method accepts a parameter that is used as the method’s ‘this’ object. We want to pass the current view into the ‘call’ method so that the prototype class can reference the model from the current view. This allows the call to ‘TemplateView.prototype.render’ to have access to the user model that the UserEditView instance is currently holding on to – the user that is supposed to be edited.

Instantiate a UserEditView and pass a user model into it with a ‘{model: user1}’ json document, and the end result is our user edit view along side our user list view.

Screen shot 2011 06 20 at 11 22 50 PM

Now the instance of the UserEditView has access to the ‘Save’ and ‘Cancel’ buttons, allowing you to bind jQuery ‘click’ events or anything else that you need to do. Toss in a little bit of data-binding code, as well, and we would have a simple form to edit users. I’ll leave that for another blog post, though.

 

Download The Code

All of the code that I’ve written for this example is available via github gists. Go grab file numbers 8 and 9 for the final working version, with both the edit form and the list of users.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Backbone, Javascript, JQuery, JSON, Model-View-Controller. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.register-domainname.in Domain Name Registration

    Rendering a template had always created headache to me especially on HTML pages. Thanks for this information.

  • Alan Huffman

    That’s good brother. I still don’t fully get the need / value of Backbone Views. Jquery template rocks of course. I think this code would be greatly simplified by using backbone for routing & models only… just create a Function(){ this.render = function(){…} } and life would be simpler.
       What’s theh value of backbone.js Views? 

    Thanks, nice post.

    • http://mutedsolutions.com Derick Bailey

      +1 for this example being done better with something like you’re suggesting, if you were building a real application.

      however, i’m not really showing any kind of best practices for the real world, at this point. i’m still learning backbone and am blogging about my experiences in learning it. the examples i’m giving are meant to be trivial and are, as you’ve noted, easily done better with other approaches. by keeping the examples simple, though, I can keep the context of what I’m saying clear and show people just the mechanics of how to do things. i think the value in using views comes into play when you have a much more complex set of interactions, with multiple areas of the page that need to be manipulated in a coordinated manner. i’ll try to talk about this more at some point in the future. right now, i’m trying to build up a baseline of knowledge so that when i do get to that, I won’t have to repeat much of the basics / mechanics

    • Anonymous

      Backbone.js views can also handle events… so you could setup a click event inside each view and when the view is clicked on, it’s handled by that specific view/model.

    • Sanood

      nice

      • Sanood

         super

  • http://twitter.com/dagda1 dagda1

    Do you think there is any performance boost from keeping the jquery templates in memory?  I seen they do this in travis.  They load all the templates into memory on the initialise of the application controller.  

    • http://mutedsolutions.com Derick Bailey

      yeah, there’s definitely some benefit to doing that, for performance reasons. i haven’t really needed to do this yet, because none of my examples have been that large. however, it’s been on my mind for a while now.

    • Anonymous

      You can also pre-compile them at init so when the views are rendered they aren’t re-compiled each time…

  • Avi Block

    The documentation also states that view or more of a convention…a good suggestion for how to organize your code. That’s, I think, why the render method is there.

  • http://profiles.google.com/bluestar007 Victor Olteanu

    Thanks for this detailed explanation. In the examples, you have Rails render ERB templates, which are then being picked up by Backbone views.  The question I have is – what about the actual model data? Currently, a Backbone model makes an AJAX request, through Backbone.sync, which hits the Rails controller, which returns the data as JSON. This JSON data needs then to be passed to the view, so that it can be “mixed” with the ERB data and rendered. But doesn’t this mean that we have to make two server request each time? So, for example, for getting an “users index” page, we would first make a call to UsersController::index requesting “JSON”, and then we would make an additional call to the same index method requesting HTML. Unless we overwrite Backbone.sync I don’t see how the Backbone models can get their data without an additional call.

    • http://mutedsolutions.com Derick Bailey

      Hi Victor,

      I render the template in my page directly, so backbone can pick it up from the page directly.  I’m not sure what scenario you’re trying to describe with backbone and getting json data from the server, either. when you call fetch from a backbone model or collection, it deserializes the data into the model for you and then you pass that to the view / template.  what additional call are you seeing a need for, when and why?

      • http://profiles.google.com/bluestar007 Victor Olteanu

        Hi Derick,

        If one calls, for example, UsersController::index, by going to http://../users, then server-side Rails will be executed first. At that point, Rails has no knowledge of whether JavaScript is supported or not by the caller (client), so it will get the list of users from the database, and render html through the erb template in views/users.erb.html.

        Now control goes to the client-side Javascript. The Backbone model User is instantiated, which does a fetch, which again calls UsersController::index, this time through an AJAX request, requesting JSON. Again the database is being accessed to retrieve the list of users.

        My aim is to be able to render HTML constructed entirely on the server-side when no Javascript is present on the client (such as a call made by a Google crawler), and to render the template on the client-side when Javascript is supported (such as an actual human accessing the site through a browser/mobile device).

        In my understanding, the goal of re-using ERB/jQuery templates is to allow SEO, which currently would not work if a Google crawler accessed http://…/users, since Javascript would be required on the client-side for rendering the actual users (ok, users is a bad example since one may not be interested in having a site’s users indexed by Google, but we can replace that by any info that we wish to have Google index).

        Thanks.
        Victor

  • Kaha

    I was wondering why people use different templating engines with backbone, if underscore already have one? Is it worth to include another templating engine for this?

  • http://register-web-domain.in/ Register Domain Name

    This is first time seeing this website You got a really useful blog

  • http://www.roymj.co.in/ Roy M J

    Hello Derick,

    Nice article. I have indeed got my application to run using partial rendering of views. However i came to a roadblock.

    By using

    the code works well.

    However if i put the template as an external file like

    this wont work.

    What is the difference between the above two methods and also how can i get around this issue? Or am i missing something here which maybe obvious?

  • dewgrass

    Please can you give us concrete examples of when we need to use ajax/json calls from our view to communicate with server and when we need to dependent of Backbone model’s RESTFUL Calls with some clear examples. Please let us know if your book deals with this kind of situation.