In this post we learn about different ways to render HTML using Backbone.js view and Underscore templates.
A Backbone view should include a render function. The render function should have the responsibility of manipulating the view’s el property. The el property is then used to update the DOM.
This post builds on the following posts:
Re-Learning Backbone.js – View Basics
Re-Learning Backbone.js – Templates (Underscore)
Re-Learning Backbone.js – Models
Here are a couple of quotes about Backbone.js Views:
“Backbone views are almost more convention than they are code — they don’t determine anything about your HTML or CSS for you, and can be used with any JavaScript templating library. The general idea is to organize your interface into logical views, backed by models, each of which can be updated independently when the model changes, without having to redraw the page. Instead of digging into a JSON object, looking up an element in the DOM, and updating the HTML by hand, you can bind your view’s render function to the model’s “change” event — and now everywhere that model data is displayed in the UI, it is always immediately up to date.” http://backbonejs.org/#View
“At a technical level, a Backbone view is simply a JavaScript object that manages a specific DOM element and its descendants.” http://aaronhardy.com/javascript/javascript-architecture-backbone-js-views/
In this first example we are going to add some text to a DOM div element.
<html > <head> <title></title> <script src="/scripts/jquery-1.7.2.js" type="text/javascript"></script> <script src="/scripts/underscore.js" type="text/javascript"></script> <script src="/scripts/backbone.js" type="text/javascript"></script> </head> <body> <div id="container-movie"></div> <script type="text/javascript"> var Movie = Backbone.Model.extend(); var MovieView1 = Backbone.View.extend({ initialize: function () { console.log("MovieView initialize"); }, render: function () { console.log("MovieView render"); this.$el.append("Title: " + this.model.get("title")); $("#container-movie").html(this.$el.html()); return this; } }); $(function(){ var movie = new Movie({ title: "Lion King" }); var movieView1 = new MovieView1({ model: movie }); movieView1.render(); }) </script> </body> </html>
In this example we created added a “div” with the id “container-movie”. We will add text to this DOM element.
In the previous post we logged everything to the browser console. Now we are ready to render content in the DOM.
Backbone.js view has a render function, but it doesn’t do anything at all. Here the code from Backbone.js source. This is the only reference in Backbone to the render function
The purpose of this simple render function in Backbone is to provide standardization. So we will override the Backbone view Render function. In our render function we append the string “Title:” and the value in the model to the “el” property of the view. We then use jQuery to find the element in the DOM with the id of “container-movie” and assign the html of “el” to the element.
When we created the movieView1 object we passed in the model, which was assigned to the view model’s property.
When we call render function, the render function is executed.
*********************************************************************
In this example we are going to use templates
<body> <div id="container-movie"></div> <script type="text/template" id="template-movie"> Title: <%=title%> </script> <script type="text/javascript"> var Movie = Backbone.Model.extend(); var MovieView1 = Backbone.View.extend({ template: _.template($("#template-movie").html()), initialize: function () { console.log("MovieView initialize"); }, render: function () { var htmlOutput = this.template(this.model.toJSON()); this.$el.html(htmlOutput); return this; } }); $(function () { var movie = new Movie({ title: "Lion King" }); var movieView1 = new MovieView1({ model: movie, el: $("#container-movie") }); movieView1.render(); }) </script> </body>
At the beginning we created a template. Since the type is “text/template” the JavaScript engine will ignore it.
Take notice that when we instantiate the movieView1 we are passing in the “el”. The “el” is set to the container that we want to update.
In the view we automatically create a template property that creates a compile version of the template.
In the render function, we are passing the model data to the template function and return the html result.
We then assign the htmlOutput to the view’s “$el” property, which is pointed to the container that we want to update.
*********************************************************
In this example we are going to pass the template when we create movieView1
<script type="text/javascript"> var Movie = Backbone.Model.extend(); var MovieView1 = Backbone.View.extend({ renderCount: 0, initialize: function (options) { console.log("MovieView initialize"); this.template = _.template(options.template.html()); this.render(); }, render: function () { this.renderCount += 1; console.log(this.renderCount); var htmlOutput = this.template(this.model.toJSON()); this.$el.html(htmlOutput); return this; } }); $(function () { var movie = new Movie({ title: "Lion King" }); var movieView1 = new MovieView1({ model: movie, el: $("#container-movie"), template: $("#template-movie") }); movieView1.render(); movieView1.render(); movieView1.render(); })
Since we are going to call render multiple times we will use renderCount property to track the number of time we call render.
When we create an object based on the view, we will pass in the template. Since “template” is not a property that Backbone merges automaticly, we need to use “options” in the initializer. In the initializer we compile the template and assign it to template. Now the template property of the view is a function that we can call.
Also in the view we are calling render. This is common in many examples I have seen.
In the render function, the template is called and passed the model data. The results of the model data is applied to the template that was passed in through the initializer. Since “el” was assigned to the container, the results are automatically applied to the DOM.
In the code we call render multiple times. What I want to show is that the same results are constantly updated to the DOM. A key practice should be that no matter how many times render is called, it should provide the same results
*************************************************************
Chaining the render function
$(function () { var movie = new Movie({ title: "Lion King" }); var movieView1 = new MovieView1({ model: movie, el: $("#container-movie"), template: $("#template-movie") }); movieView1.render().$el.append(" - Great Movie"); })
In the previous examples we returned “this” from the render function. By returning this, we are able to chain the results of render.
Thanks for taking the time to make these backbone.js walkthroughs.