There is a better way to write Backbone applications and here I hope to write a quick primer. The topics I will cover in this series will follow these basics:

  1. Everything-from-one-container
  2. Pass-through views
  3. Declarative rendering
  4. Abstract away element access (TBD)
  5. ViewModels over Models (TBD)
  6. BONUS ROUND Coffeescript (TBD)

Everything-from-one-container

Often when evaluating other backbone applications I will see somewhere deep in the program a line of code like this:

render: function() {
  for(var i = 0; i < this.items.length; i++) {
    $('#table').append(_.template('item_template', { item: this.items[i] }));
  }
}

This code is appending to the element with id table N number of items. The biggest issue with this code is that it is not a self contained view. If there happened to be another element with id table on the page, it would add the items in two places (while also being malformed HTML). We could solve this scoping the selector to the element represented by the view. So instead of $('#table') we would use this.$el.find('#table'). This solves the immediate problem of scope, but the code here has another hidden dependency.

It depends on the fact that whatever element the view is bound to has an element with id table as a descendant. This makes the code less portable and more tightly coupled to a global resource. We can improve the code by instead appending the children to the element that the view is bound to. So the code would go from this.$el.find('#table').append to this.$el.append. This removes that external dependency and simplifies our code itself.

If we apply this principle to the extreme in our application, we will find that we are pushing more and more of our bindings "up" from the leaf nodes of the tree all the way to the root node. Eventually, we will only be left with one binding. That is the binding that the application initially goes into. This is the "one container" form. You start your application with code like this new MyApp({el: $('body')}) and, because we can inject the one HTML dependency at creation, we have successfully removed all dependencies on the static HTML that we render to the client. Our application is extremely portable and can be dropped into any HTML resource.

So, the app may look something like this

MyApp(el: some-html-element)
  append MyApp.Header
    html template 'header'
  append MyApp.Sidebar
    html template 'sidebar', { items: objects }
  append MyApp.Content
    html template 'content', { item: selectedItem }

Conclusion

With the 'one container' form/pattern, we have eliminated one of the hairiest problems in Backbone -- the disconnection between the static HTML resource and the application itself. We did this by removing our reliance on the static HTML resource altogether and to make the app truly self driven.

In next post (which I am writing now!), I'll talk about how to write views so that we can begin to build a modular, testable application that adheres to the principles of SRP and DRY.