JavaScript is more important than ever for building highly interactive Web applications. Libraries and frameworks, such as Backbone.js, Marionette.js, Ember.js, and Angular.js are popping up and growing quickly in both popularity and features. These libraries and frameworks make it easier to build very complex and powerful applications in a browser. They help usher in a new era of Single Page Applications (SPAs), creating an unprecedented level of interactivity and usefulness on the Web.

But not every Web app or every page on a site needs to be built with a SPA framework in order to be interactive. A lot of applications are better suited to a smaller scale of functionality. For these pages, there is a need for a high level of interactivity without the need for client-side routing and other SPA features. With a reduction in functional requirements for smaller pages, there is also a reduction in the list of appropriate frameworks and libraries for building the page. You don't need a complete MVC framework just to add form validation, for example. Many developers choose to write code with nothing more than jQuery when they don't need a complete SPA framework, and with good reason. The interactivity provided by jQuery can be easily augmented with plug-ins and add-ons to create further interactions.

One of the difficulties in building large jQuery applications is keeping code organized. It is very easy to get lost in a Christmas tree of doom-a deeply nested list of callback functions that seems to hold every single feature and interaction. The truth is that jQuery does not provide any guidance on organization or structure for code.

The good news is that you don't have to choose exclusively between jQuery and well-structured code that SPA libraries and frameworks help you to write. You can combine the simplicity and interactivity of jQuery-based applications with the building blocks of good structure from Backbone.js to create highly interactive pages that also have good code organization and structure.

What is Backbone.js?

Backbone.js is a library of components that helps developers add structure to JavaScript code in Web applications. From BackboneJS.org:

“Backbone.js gives structure to Web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and then connects it all to your existing API over a RESTful JSON interface.”

Backbone.js includes a handful of building blocks that provide a distinct set of features, including:

  •     Model: An object with attributes comprised of key-value pairs. Models encapsulate the data and associated behavior of data within an application.
    
  •     Collection: A collection of models. Collections allow groups of related models to be held together and managed as a whole. Common collection features such as adding and removing, iteration, filtering are provided.
    
  •     View: A generalized collection of methods and the configuration for managing and manipulating the DOM, and for displaying data from Models and Collections. Views provide a well structured approach to using jQuery's DOM events, they allow easy rendering of HTML templates, and more.
    
  •     Events: A minimal yet robust implementation of the observer design pattern for JavaScript objects. Events glue Backbone.js applications together. Every object in Backbone.js includes the Events system, allowing every Backbone.js object to trigger events and handle them.
    
  •     Router and History: A set of objects that manage the browser's history with URL hash fragments or HTML5's pushState technology. Routers and the History object allow an application state to be bookmarked or linked, reloading the page to exactly the place where it was left.
    

There are other small parts of Backbone.js, still, that become important to understand if and when they need to be customized. For a high level overview and for most applications, though, these six objects are the most important.

Looking beyond the individual pieces of Backbone.js, there is some debate about what to call it from an architecture and patterns perspective. Backbone.js fits within the Model-View-* (MV*) family of patterns quite clearly. It provides a set of objects that help to organize models and views, after all. But it doesn't quite fit into an MVC pattern, or MVVM pattern, or MVP, or anything else. It's easiest to call Backbone.js a member of the MV* family. Beyond this, it doesn't make much difference what people call it.

Building a Contact List

Dozens of application types require the storage and retrieval of contact information for other people, such as a CRM system, a time tracking app, accounting, or any of a number of other things. And although a contact app may not have the most exciting feature set ever, it provides a great example of an app that could use a high level of interactivity, but doesn't need to be a SPA.

A simple contact list only needs a handful of features:

  • List of contacts
  • Add a contact
  • Edit a contact
  • Delete a contact
  • Contact data

It also needs data for to go with these features, including:

  • Name
  • Photo URL
  • Email address
  • Phone Number
  • Notes

A simple contact list used in learning the basics of Backbone.js only needs to handle a single email address and phone number. You would want to allow multiple phone numbers and email addresses in a real application, but Backbone.js doesn't have nested or hierarchical models built into it. This makes it slightly more challenging to handle multiple values or nested objects and collections, although it's not difficult to add this functionality with a plug-in A single email address and phone number will suffice for this application.

The layout for this application can be simple, as shown in Figure 1 and Figure 2. It only needs a list view and a single form to add and edit a contact.

Figure 1: This is the add contact form.
Figure 1: This is the add contact form.
Figure 2: This is the sample contact list.
Figure 2: This is the sample contact list.

When you click the Add button, the form displays, allowing you to add a new contact. Clicking save sends the contact to the server. Clicking cancel clears the form and hides it again.

From the list of contacts, clicking the Edit button shows the same form as the Add process, but populates the form with existing contact information. Clicking save sends any edits that were made back to the server. Saving also updates the contact list with the latest information. Canceling discards any changes that were made and does not update the list.

An API Server

Backbone.js works best with servers that provide a REST-like API for data. This is easy to set up in most programming languages, include Ruby on Rails, NodeJS, ASP.NET MVC (with WebAPI), Python's Django, various PHP frameworks, and more. The important aspect is not the technology stack that the server uses. Rather, the emphasis is on the REST-like API that is provided for the various resources.

Backbone.js was developed in a Rails world and expects the API it communicates with to look like a Rails-generated API. Any resource that a Backbone.js app works with should have an API on the Web server that accepts and returns JSON, and conforms to the Rails URL and HTTP verb conventions.

In the case of a contact list, the API might look like this:

  •     GET /contacts: Return all contacts
    
  •     POST /contacts: Create a new contact using the data from the form, posting it as a JSON document.
    
  •     GET /contacts/:id: Get the contact specified by the :id parameter
    
  •     PUT /contacts/:id: Update an existing contact using form data that was posted as a JSON document. The contact to update is identified by the :id parameter
    
  •     DELETE /contacts/:id: Delete the contact specified by the :id parameter
    

The contact application built in this article is technology and server framework agnostic, as long as the server conforms to this basic API structure. How you implement the server stack is entirely up to you.

The Add Form

The first thing that needs to happen in the JavaScript for this app, is to handle the Add button click. Add a standard jQuery DOMReady callback function to ensure that the DOM is ready and available. Then, inside of the DOMReady callback function, add a jQuery selector that finds the #add element and listens to the click event. Call preventDefault on the event args to make sure the button click doesn't post back to the server.

$(function(){

  $("#add").click(function(e){
    e.preventDefault();
    showAddForm();
  });

  // other code will go here ... 

});

Within the event's callback function, a call to showAddForm is made, to show the add form. This function finds the #add-edit-form element and shows it using an animation.

function showAddForm(){
  var form = $("#add-edit-form");
  form.slideDown();
}

Next, add an event handler for the click event of a #save button. This button exists within the #add-edit-form, but it can also be selected by ID, directly. Within this click handler, grab all of the data from the form input elements and post it to the server to create a new contact. When this is done, update the list of contacts with the new contact information, as shown in Listing 1.

When the POST back to the server succeeds, it calls the updateList and clearForm functions, which do what you expect (the code for these has been omitted, for brevity).

Without completing the functionality for this simple application, you can see that the code is quickly turning into a mash of functions hanging out in the middle of nowhere. This style of loosely structured code is fairly typical for small pages with jQuery. Nearly every JavaScript and jQuery developer has written similar code, and this style will continue to be popular as it gets the job done for small tasks

It is possible to write well-structured jQuery code, even if you aren't using a framework or library to provide that structure, of course. That tends to lead to re-inventing things when you should be focused on getting things done. Instead of spending time on building underlying structure, use the models, collections, views, and other types that Backbone.js provides and migrate your application in to a better structure, one step at a time.

From jQuery to Backbone.js: A Migration

It's tempting to jump straight in to Backbone.js at this point, but that would be a disservice to most developers. Starting from scratch is easy. The real challenge lies in taking existing code and migrating it to something else.

Taking a migration approach to Backbone.js does two things:

  • Shows that Backbone.js can be added to existing projects, without an all-or-nothing re-write
  • Shows the similarities and differences between writing jQuery on its own and using Backbone.js to structure jQuery

The Add form that was built with plain jQuery code will be migrated to Backbone.js, one step at a time. Before that can happen, though, you'll need to configure Backbone.js in your project.

Setting up Backbone

Backbone.js technically only has one hard dependency: Underscore.js. Underscore.js is like Batman's utility belt: an indispensable collection of tools, utilities, and toys that make JavaScript easier to work with. It brings many features of other languages, and some features from future versions of JavaScript, into existing browsers. Underscore.js, like Backbone.js, was created by Jeremy Ashkenas, and is maintained in the DocumentCloud organization on GitHub.

If you want to use Backbone.View to organize your DOM manipulation and interaction code, though, you also need a DOM manipulation library; jQuery is the natural (and most popular) choice in this case.

Lastly, Backbone.js works with a JavaScript document format called JSON. All browsers support the JSON format natively these days. If you need to support older or specialized browsers that don't support JSON directly, you will need to include the JSON2.js library from Douglas Crockford, the creator of the JSON standard.

With all of these files downloaded into a /js folder in your project, the script tag references in your HTML will look like this:

<script src="/js/json2.js"></script>
<script src="/js/jquery.js"></script>
<script src="/js/underscore.js"></script>
<script src="/js/backbone.js"></script>

Note that the order is somewhat important. Backbone.js must be listed after jQuery and Underscore.js. If you don't get at least this part right, Backbone.js won't work properly.

Once you have Backbone.js' needed files in your project and referenced in your HTML, you can get started with the migration.

Backbone.View and the Add Form

Backbone.View is the easiest way to introduce Backbone.js into an existing application. At its heart, a Backbone.View is nothing more than a few simple conventions for organizing jQuery code. Of course it allows for much more than just that, but starting with jQuery code organization makes it easy to get going.

Getting started with nearly anything in Backbone.js requires a call to extend the base type that you want to work with. If you're familiar with Java, this method name should sound familiar. If you're familiar with C#, this is the equivalent of ":" with a base class. The extend method in Backbone.js is how inheritance is done.

var AddForm = Backbone.View.extend({
  // add configuration, methods and behavior here
});

By extending from a base Backbone.js type, you can create your own specialized types that do the things you need in your application. In this case, you're creating a new View type called AddForm. This represents and works with the DOM elements for the #addform, which is the same form element that was previously manipulated by raw jQuery.

Within the { and } of this view definition, you can add your view's specific configuration, methods, and behavior. There are a number of configuration options and methods that Backbone.View recognizes and uses on your behalf. However, most of the code you write will be of your own design.

Rendering the #addform Input Fields

The most common function to add to a Backbone.View is a render function. The base Backbone.View has this method built into it, but it doesn't do anything more than return the view instance. It is effectively a no-operation method. This core method exists so that any application or framework can call a render method on a View instance.

Add a render method to your AddForm by declaring the method name with a “:” separating the name from the function. This is JavaScript's object literal syntax, and it's the syntax used to define Backbone.js types.

var AddForm = Backbone.View.extend({

  render: function(){
    var rawTemplate = $("#add-form-template").html();
    var compiledTemplate = _.template(rawTemplate);
    var renderedTemplate = compiledTemplate();
    this.$el.html(renderedTemplate);
    return this;
  }

});

There are only five lines of code in this view, but each of them is significant.

The first line loads the HTML contents of a DOM element into a variable called rawTemplate. This is an HTML template in the same sense as a server-side HTML template. It is a collection of HTML tags, with or without special markup for data and behavior, that can be used to generate raw HTML. You'll be adding this template to your HTML page in a moment.

The second line compiles the template in to a JavaScript function. In this case, Underscore.js is used as the template engine because Backbone.js relies on Underscore.js so it is already available in your application. Calling the_template method and passing in the raw template HTML compiles the HTML to a function. This function is then ready to produce the final HTML output from the template.

The third line executes the compiled template and produces HTML output from the template. In this case, the method is called with no parameters. If data is needed in the template, though, a JavaScript object can be passed in. The names and values of the attributes on that object are used to populate the template. You'll see this later on.

The fourth line takes the rendered HTML and stuffs it into the view through the $el attribute of the view. The $el attribute is a jQuery selector object that represents the DOM element that this view instance manages. Every view instance has a $el attribute and by default, it's a

element (although this can easily be changed). When working with a view instance, all DOM manipulation happens through the view's $el - including reading data, writing data to the DOM, updating CSS classes, animations, and any other work you would do with jQuery. The view is effectively an encapsulation of behavior for a given DOM element and its child elements.

The last line of this method returns the view instance. This allows you to chain methods and attribute access into a single line after rendering the view.

A Template to Render

In the render method for the AddForm, an HTML template was referenced using a jQuery selector. The contents of the #add-form-template DOM element were then extracted and run through Underscore.js' template method. For this to work, you will need a DOM element with the right ID and contents. But you don't want that DOM element to show on the page. You only want it available for rendering as a template. There are several ways to do this, the simplest of which may not be obvious: using a <script> tag.

Add a