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.

  • http://twitter.com/dmosher Dave Mosher

    A good article that breaks down what happens for beginners step by step. I would just add one minor addition to your “Putting it all together” heading that explains a common convention for render functions: from the backbone docs (http://documentcloud.github.com/backbone/#View-render)

    “A good convention is to return this at the end of render to enable chained calls.”

  • http://jclem.net Jonathan Clem

    Nice article. I typically prefer the view to be agnostic about what element it’s actually rendered into, so my render functions tend to look like this:


    render: function() {
    var output = this.template({ model: this.model });
    return this.$el.html(output);
    }

    And when I actually need to render a view, I do something more like this:


    $('#content-wrapper').html(view.render());

    That way my view isn’t bound to any one specific DOM element.

    • http://twitter.com/dmosher Dave Mosher

      The only issue with the way your render is returning is that you explicitly return the jQuery/Zepto wrapped DOM element, this is problematic because you sometimes just want the non-wrapped view.el property. The idiomatic “backbone way” to achieve this is to have your render function return this as its final statement. ie:

      render: function() {
      var output = this.template({ model: this.model });
      return this.$el.html(output);
      }

      • http://jclem.net Jonathan Clem

        I wouldn’t say it’s an issue, as I’ve never wanted the non-wrapped view.el property. However, I will agree with you that this approach is more idiomatic.

  • http://tbranyen.com/ Tim Branyen

    You have a typo in there.

    var app.myModel = new Backbone.Model({ ‘name’: ‘Joe’, ‘city’: ‘New York’ });

  • Diego

    Thanks, I’m starting with Backbone and this articule is really helpful.

  • http://www.facebook.com/lambdanaut Josh Thomas

    Seeing all of this code in a repository somewhere would be immensely helpful. I always get confused when I don’t know what code goes into what files, though perhaps it’s simpler here than I’m making it out to be.