http://www.developer.com/lang/jscript/creating-a-javascript-driven-online-notebook-with-backbone.js.html

Back to article

Backbone.js: Apply MVC to Your JavaScript-driven Applications


May 13, 2011

I'm probably seriously dating myself with this question, but have you ever seen the movie "Can't Buy Me Love"? It's about a high school outcast named Ronald Miller who teams up with a cheerleader to raise his social prominence. JavaScript was in many ways the Ronald Miller of programming languages until Jesse James Garrett coined the term Ajax back in 2005. Suddenly, JavaScript had a new lease on life, and thanks to an extraordinary amount of attention over the past several years it has risen to become one of the most sought-after programming languages in the world.

In fact, many of today's hottest Web technologies are JavaScript-based, among them jQuery, CoffeeScript and Node.js. These technologies open up the possibility to build Web applications that are entirely JavaScript-driven (on both the client and server side)!

As JavaScript-driven applications become increasingly sophisticated, developers have been hard at work devising tools that help them to design rock-solid application architectures. One such tool is Backbone.js, which helps you to apply the MVC principle to your JavaScript applications. In doing so, you can greatly reduce the complexity otherwise involved in synchronizing changes between your application's view, logic, and database. In this article I'll introduce you to Backbone.js, highlighting some of the key features that make this library so appealing.

Installing Backbone.js

Despite its considerable capabilities, Backbone.js is packaged into a 3.9kb file. Head over to the Backbone.js site to download the latest production version. There you can also optionally download a commented version if you'd like to browse the source. You'll also need to download Underscore, a JavaScript utility library that offers dozens of useful helper functions. For the following examples we'll also use jQuery, which I'll reference via the Google CDN. Finally, we'll use a localStorage adapter in order to persist the notes on the client's machine. Be sure to reference the files in the correct order, as demonstrated here:

<script src="http://www.google.com/jsapi" type="text/javascript" target="_blank"></script>
  <script type="text/javascript" target="_blank"></script>
    <script src="underscore-min.js" target="_blank"></script>
  <script src="backbone-min.js" target="_blank"></script>
<script src="backbone.localStorage-min.js" target="_blank"></script>

Creating a JavaScript-driven Online Notebook with Backbone.js

The Backbone.js website includes a great Todo list example, however if you're just starting to explore the library even this simple example can be a bit overwhelming. So in this section I've created a simplified variation of the example, capable of merely updating the page to reflect new notes. The finished project is presented in Figure 1. Once you're able to grasp this simple example, definitely consider checking out the Todo list example, as it incorporates numerous other useful features.

The online notebook application consists of three distinct components: a model representing a note, a model representing a series (collection) of notes, and a model representing the notebook, or application.

A Persistent Web-based Notebook Built with Backbone.js
Figure 1. A Persistent Web-based Notebook Built with Backbone.js

The first step you should take is to create a model representative of a note. This model will define the note's properties and behaviors. We're going to keep this simple and define one single property:

window.Note = Backbone.Model.extend({
  snippet: null
});

Creating the Notebook

Next we'll define the model that represents the notebook, or a collection of notes. Notice how this model definition differs from the previous in the sense that we are extending Backbone.Collection rather than Backbone.Model:

window.Notes = Backbone.Collection.extend({
  model: Note,
  localStorage: new Store("notes")
});

window.Notebook = new Notes;

The model property determines what sort of object's make up the collection, which in this case is the Note model defined previously. The localStorage option tells Backbone.js to store the collection in a container on the client. This is an incredibly useful feature for this type of application since the application maintainer doesn't have to deal with storing the user's notes in a database. Finally, following the definition we'll instantiate the model.

Creating the Note View

The NoteView structure presented below determines how each note should be rendered. This is in my estimation the trickiest part to understand. It is responsible for inserting each note into a template (presented below), which is embedded into the page and otherwise not visible to the user.

window.NoteView = Backbone.View.extend ({

  initialize: function() {
    _.bindAll(this, 'render');
    this.model.view = this;
  },

  template: _.template($('#item-template').html()),

  render: function() {
    $(this.el).html(this.template(this.model.toJSON()));
    this.setContent();
    return this;
  },

  setContent: function() {
    var snippet = this.model.get('snippet');
    this.$('.note').text(snippet);
  }

});

The #item-template template DIV looks like this:

<script id="item-template" type="text/template"></script>

Defining the Application View

All that remains is to tie everything together by defining a view for the entire application, presented below. The el property determines where on the page the "application" exists. Next, the initialize method executes every time the application loads. Note in particular how it binds application view methods to methods residing in the Notebook model (some of these are available by way of the extension, meaning you don't explicitly define them). These bind() calls really sum up the beauty of Backbone.js, allowing you to trigger methods residing in other models based on some page-specific action, such as reloading the page.

I'll talk further about this view following the listing:

window.AppView = Backbone.View.extend ({

  el: $("#notebook"),

  initialize: function() {
    _.bindAll(this, 'saveNote', 'updateNotebook', 'addAll');

    Notebook.bind('add', this.updateNotebook);
    Notebook.bind('refresh', this.addAll);
    Notebook.fetch();

  },

  events: {
    "click #submit": "saveNote",
  },

  addAll: function() {
    Notebook.each(this.updateNotebook)
  },

  updateNotebook: function(note) {
    var view = new NoteView({model: note});
    $("#notes").append(view.render().el);
  },

  newNote: function() {
    return {
      snippet: $("#note").val()
    };
  },

  saveNote: function() {

    Notebook.create(this.newNote());
    $("#note").val("");
  }

});

window.App = new AppView;

The events object literal binds events to methods, causing these methods to fire when the associated event occurs. The addAll() method will execute automatically every time the page loads. Therefore we're going to iterate over the notebook, adding each note to the page. The updateNotebook() method will render a note to the browser. Contrast this with the saveNote() method, which triggers the note create() method in the Notebook model.

Where to From Here?

Admittedly, tracing the execution is by far the hardest part of understanding Backbone.js, so I suggest using the above code to recreate the application, and then insert various alert statements to watch how Backbone.js jumps from one model and view to the next. After a few minutes you'll really start to get a feel for the process, and can then begin to appreciate just how powerful this approach really is.

About the Author

Jason Gilmore -- Contributing Editor, PHP -- is the founder of EasyPHPWebsites.com, and author of the popular book, "Easy PHP Websites with the Zend Framework". Jason is a cofounder and speaker chair of CodeMash, a nonprofit organization tasked with hosting an annual namesake developer's conference, and was a member of the 2008 MySQL Conference speaker selection board.

Sitemap | Contact Us