Putting some MVC meat into your app: Backbone.js

June 7, 2012
By

Hey, everyone. Luc here, coming at you with a brief look at Backbone.js, which is becoming less of a secret by the day in the world of web development. Evidence? It’s currently the 9th most-watched repository on GitHub and is showing no signs of slowing down. In addition, BackboneConf, which was held last week in Boston, seems to have been a big success, at least judging by the live tweets in my Twitter feed.

Backbone essentially provides you with the kind of architecture that you would find in other web development frameworks–Rails being a classic example–but does so in JavaScript and completely in the front end, without needing to resort to the back end for persistence. Why do such a thing? Well, let me ask you another question: do you want to try and set up an MVC-style framework from scratch in JavaScript? Me neither!

But having an MVC-style architecture on the front end strikes me as eminently useful, for at least one simple reason: it enables you to generate and manipulate new objects within your view(s) according to a specified data model, just as you would generate, say, blog posts using class Post in Rails, and also to gather your models into collections and to subordinate some models to others (the way that you would use, say, class Post < User in Rails).

Here’s a brief list of the very cool things that I have discovered about Backbone thus far:

1. Views within views (within views within views…). Like much else that is JavaScript-based, Backbone interacts with HTML via the DOM. This might seem more tricky than using Rails to render views, but it ends up harboring the very nice advantage that a change within a Backbone-based app–say, adding an element to a list being displayed–can induce a change within one of many sub-views being presented on the page.

This is simply not possible if you’re using something like Rails for the front end of your app, because Rails has to go back and re-render the entire view. In Backbone, you can set things up to re-render only the document object being targeted, be it a div or a paragraph or a list item or the entire body.

2. jQuery interoperability. Like I said above, chances are pretty good that you’re already using a lot of JavaScript if you’re doing front-end web development. Backbone is nice because it unsurprisingly integrates seamlessly with libraries like jQuery (in fact, the Backbone library depends directly on jQuery).

Here’s a code example. Let’s render a DOM object, in this case our container. This is done via the “render” method that is called up within our view (or one of our multiple views):

render: function() {
    $(‘#container’).html(this.template());
    return this;
}

You probably recognize the “$” from jQuery, used to target DOM objects. Here, the div named container is being targeted to be rendered according to a template specified earlier (and templating can be done either in your HTML page or behind the scenes in a separate JavaScript file).

Even more usefully, Backbone is flexible enough to allow you to specify specific DOM elements as being whole views in themselves if you so wish, even <li>s or <p>s or <span>s. You could have, say, divs named “header,” “body,” and “footer,” and each could be set up to respond to “listen” to input and re-render themselves independently of one another. Which brings me to…

3. Binding. The idea of an event-driven interface isn’t the most intuitive thing in the world, but one of the things that really made the concept come alive for me is the idea of binding. Let’s say I’m setting up a view, and I include this as one of that view’s methods:

initialize: function() {
    this.model.bind("change", this.render, this);
}

Upon initialization, the “bind” method listens in, so to speak, for any change undergone by the model that is bound to the view. Example: we use a function called addItem to add the new object peanutButter to the list “tuesdayShoppingList.” This list was built according the “ShoppingList” data model, which we tie directly to a view called “shoppingListView.”

As soon as “peanutButter” is added, the view will “sense” this via binding and will be re-rendered. If this view is only part of our page–let’s say it corresponds to the jQuery element $(‘#tuesdayShoppingList’) in our DOM–then only that part of the page will be re-rendered. If our “tuesdayShoppingList” is tied to a <ul>, then our new item will pop up in the list.

Even more useful: this ability to engage in partial rendering and re-rendering allows us to quite nicely bake asynchronicity into our views. If we’re using a back end like node.js that supports asynchronicity, then this is a crucial asset to be able to use in conjunction with our server.

4. Controller or no controller? While there’s a router built into Backbone, there’s nothing exactly analogous to the kind of explicitly-defined controller that one finds in Rails. Instead, what you have is a kind of implicit controller that functionally resides in the way that you organize your system of models, views, and event triggers (such as the one described above).

Models, on the other hand, function in a way that is perhaps more like what one would find in Rails. If you’re making a new data model called “Person,” your code would look something like this:

var Person = Backbone.Model.extend({ … });

The … is where you would specify your default values as a hash, tell Backbone what to do upon initializing the model, and list the properties and methods associated with the objects that will correspond to the model. You could then instantiate an object constructed according to this model like this:

var lucPerkins = new Person({ name: “Luc Perkins”, profession: “developer evangelist” });

Your controller, however, would work differently. It would result as an emergent property, a kind of deus ex machina, of the way that you have set up your models and views. The difficulty with this, of course, is that there is no location within your app where you can easily see all of the things that your implicit controller is doing, e.g. how your event sequences are laid out.

I must say: watching an app slowly come together that works, in which clicking a button in one view produces object instances of a specified class and then semi-magically has instant effects in another view, is immensely satisfying.

One final advantage: Backbone is compatible with any back end that can interact with JSON. You can run Backbone on Rails, in Java, Python, whatever. A person could be a full-time Backbone developer and work with models and collections and persistence but never once be all that worried about databases or server architectures.

I should note that these features–binding, partial views, etc.–are not exclusive to Backbone. Knockout.js and Ember.js, for example, offer similar possibilities for binding DOM elements to events and working with persistence in the front end. I will have more to say about both in the coming months.

In a later post, I’ll put Backbone to work using Rails on the back end. Fortunately, there’s a lot that’s already been done on this and I will not be walking alone. Coordinating these two architectures across languages (Ruby and JavaScript) will be difficult, but I’m excited to do so because I think that it will begin to really expand my ability to think and work as a polyglot.

If you’re interested in seeing some of the essential elements of Backbone at work, here’s an example of a page that I put together with Backbone, with a noticeable reliance on this app as a basis. You can see the code on GitHub (much more on GitHub in future posts).

It allows you to generate generic list items in accordance with the model Item by clicking the “Add list item” button. Each list item that you generate is associated with a number (producing using a simple counter++ in JavaScript) as well as several options that you can click on. Clicking on these options (lodged in <span>s) triggers events that affect different views:

[swap] switches around the name of the list item
[delete] removes the list item
[size change] makes the font of the entire list item larger
[bold] makes the font of the list item
[fancy] makes just the list item disappear and come back (using jQuery’s fadeIn( ) and fadeOut( ) functions)
[whoa] makes the entire body disappear and come back

Clicking “Reset the counter” doesn’t actually destroy any list elements, but rather means that the next list item you generate will be called “list item 1.”

So why was Backbone so instrumental in making something like this? What’s going on here that isn’t just jQuery or CSS or HTML?

The crucial difference is that generating list elements that share a common structure like this can’t really be done unless there’s a persisting data model that supports them. JavaScript doesn’t come out of the box with this kind of capability built in, but Backbone is one of the most successful ways yet devised of putting this capability at developers’ fingertips.

 

Tags:

Read from Source

PaasMag

Paasmag Logo

Twitter

Paasmag Twitter

Tweets

#6: Architecting the Cloud: Design Decisions for Cloud Computing Service Models (SaaS, PaaS, and IaaS) ... pic.twitter.com/8ZCMHaTGkD