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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
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.