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)

Pass-through views

In the old days (and still current for the unlucky few) of .NET web application development, there was a framework called WebForms that developers would use to create web applications. WebForms used a system called "CodeBehind" that allowed developers to interact with objects in the views.

The .NET community has since grown and the MVC/MVP stack is widely regarded as superior. The idea of separating views from handling user interactions is something that most developers are keenly aware of these days.

However, with Backbone I often see some regression. For example, it is not uncommon for me to see something like this:

events: {
  'click .item' : 'selectItem'
},

selectItem: function(e) {
  var id = $(e.currentTarget).data('id'),
      item = this.items.get(id);
  _.each(this.items, function(i) { i.selected = false; i.save(); });
  item.selected = true;
  item.save();
  detailView.setItemSelected(item);
  return false;
}

What we are doing in this view is grabbing the associated item, clearing selections of other items, modifying it, saving it and telling another view that the item is selected.

Let us assume we are okay with this code. We push it to production. It works. Everyone is happy. Then, we get a customer request to be able to clear selection with an "x" in the detailView. A common pattern that doesn't seem unreasonable. We add the following code:

events: {
  'click .clear-selection' : 'clearSelection'
},

clearSelection: function() {
  _.each(this.items, function(i) { i.selected = false; i.save(); });
}

Again, the code works well and gets the job done. However, being lazy developers, we notice that we have written the exact same code twice. How would we deduplicate this code? We extract it to a class.

var SelectionService = function(items) {
  this.items = items;
  return this;
}
_.extend(SelectionService.prototype, {
  clearSelection: function() {
    _.each(this.items, function(i) { i.selected = false; i.save(); });
  },

  selectItem: function(id) {
    var item = this.items.get(id);
    this.clearSelection();
    item.selected = true;
    item.save();
  }
});

And then we would use the class service.selectItem(id) and service.clearSelection(), respectively, in our code to reduce the amount of duplication. As your application becomes more and more complex, these components will be shared amount more views of your application. The goal to to create views that only render and delegate user interaction to the appropriate "service" classes. You can call them controllers, if you wish.

Conclusion

In this we talked about making your views smaller by having them delegate to another class. This other class can be shared among other views without having to duplicate code or logic.

There is still more that can be done to clean up this view (i.e. the setSelectedItem call to the other view). We will discuss this in the next post.

NOTE There is another way of sharing code and that is through mixins. I did not talk about them here but I definitely recognize their existance. It is my belief that they are not useful in this context but others may disagree.