A Backbone.js Render Method Explained for Beginners
When I first picked up Backbone, it took a while before I fully grasped how a normal render method works because I was coming from a background of superficial DOM editing with jQuery. Backbone doesn’t provide a default render method, but most Backbone tutorials and examples use a very similar method. If you’re not very experienced with JavaScript and jQuery, it can be hard to start learning a library like Backbone as it will take a while before you even get anything to show up in the browser.
Now that I’ve worked with Backbone for several months, I’ve become much better acquainted with plain JavaScript, too. Working with Backbone forces you to internalize core JavaScript concepts and patterns such as scope, prototypes, namespacing and more. So if you want to get into writing web applications with JavaScript, I recommend jumping straight to Backbone and learning alongside it.
Here’s the tutorial explaining the Backbone render method I would have needed when I first picked up Backbone. Let’s begin with the view template.
Template
First thing we want to do is have a template containing html code, and inside that template we have variables. Here’s an example in which we want to show a name and an city, perhaps for a user profile.
<script type="text/template" id="contact-template">
<div class="name">
<%= name %>
</div>
<div class="city">
<%= city %>
</div>
</script>
This markup should be included in the document before closing the <body> tag or loaded as a .js file.
The <%= %> elements inside the two div’s indicate a variable for Backbone’s default templating engine provided by Underscore.js.
The html markup is wrapped in script tags with a type of text/template so that the browser doesn’t interpret it as Javascript while also remaining unrendered in the browser for now. We will do this rendering with Backbone.
Data
We need to provide the values of name and city in order to successfully render the view. What you usually want to do is get that data from a Backbone model.
A common practice is to bind a model to a view. This is done by creating a model property for the view and pointing it to the model.
var app.myModel = new Backbone.Model({ 'name': 'Joe', 'city': 'New York' });
// inside the view object, we set it's model property ...
this.model = app.myModel
Combining template with data
When called with one argument, the Underscore template function _.template() only takes the template markup as an argument and returns a function that can take data and fill the template’s variables with it.
Let’s create a template function for our contact template with Underscore:
var templateFunction = _.template( $("#contact-template").html() );
// Essentially same as _.template( "<div class="name"> <%= name ... " );
The template function takes a string argument containing the template markup. A convenient way to do this is use jQuery to select the script element we just created, and get it’s content with jQuery’s html() method.
Once we’ve created our template function, we can supply it with data to fill the template:
var output = templateFunction( data );
Oh right, we need the data. The Underscore template method wants it in the form of a Javascript object with properties that’s names correspond to the variables set in the template. We could supply data like this:
var data = { name: 'Joe', city: 'New York' }
/* data is now a variable holding a Javascript object
with properties name and address */
And the template would be rendered as expected. However, we would like those properties to come from a Backbone model. Unfortunately you can’t supply the template function a plain Backbone Model object, you have to call Backbone’s toJSON() method on it which returns the data as above.
var data = app.myModel.toJSON();
// Essentially same as var data = { name: 'Joe', city: 'New York' }
Cool. Now that we have the data, we get the proper output.
var output = templateFunction( data );
Returns
<div class="name">
Joe
</div>
<div class="city">
New York
</div>
Getting the view to show up in the browser
Right now the markup we want to show exists only as a Javascript string. It doesn’t exist in the web page seen by the user. Let’s get it on the page.
Usually you’ll want to select an existing element from the document such as #content-wrapper that I’ll be using here and replace it’s content with your template output. With Backbone you can also create any element to surround the template and append it to the document which can come in handy when creating something like a list. A Backbone view has tagName, className and id properties that you can use.
Let’s get our template on the page by first selecting an existing element.
var myElement = $( '#content-wrapper' );
If we call jQuery’s html() method on myElement with a string argument, myElement’s content’s will be replaced with the submitted string.
myElement.html( 'Cool' );
Instead of ‘Cool’ we want to submit our rendered template. Easy:
myElement.html( output )
And in the browser we get:
<div id="content-wrapper">
<div class="name">
Joe
</div>
<div class="address">
New York
</div>
</div>
Putting it all together
A render method could look like this:
var template = $( '#contact-template' ).html();
// Get our template as a string
var templateFunction = _.template( template );
// Returns a function that will fill template variables
var data = this.model.toJSON();
// same as var data = { name: 'Joe', address: 'New York' }
var output = templateFunction( data );
// Returns a string containing template with filled variables
var myElement = $( '#content-wrapper' );
// Pick an existing element from the document that's content we will replace
myElement.html( output )
// Finally get the rendered template to the document
But if you’re a Javascript Ninja or Backbone Rockstar, you’ll probably do it all in one statement:
$( '#content-wrapper' ).html( _.template($('#contact-template').html(), this.model.toJSON()) );
Just kidding.
What’s next?
There’s plenty more to managing Backbone views and their rendering. They can leave zombies. They have pitfalls. With great freedom comes great responsibility, and your best bet could be to use a framework on top of Backbone such as Marionette once you understand why you benefit from it.