← home← blog

A Backbone View to a Kill

09 Jun 2013

Backbone is awesome. It allows you to write large scale apps but still keep control of the code you're writing (read: it doesn't do all that much for you).

However, a lot of people struggle (people, being me, for ages) to level up from the 'Todo' App in the early stages. Hopefully this post and the related GitHub repo will assist you nicely.

We're going to be using Dan Harper's sweet ViewManager for our post's code. It's nowhere as sophisticated as something like Marionette.js, however it does give you a really nice method of controlling/destroying the Views within your application.

The one thing that confused me when starting out with Backbone.js, was actually creating a real world application, ie. an app with lots of different states, lots of different "areas" or "regions" - sidebar, header, content, etc...

ViewManager

So I thought, lets use Dan Harper's ViewManager to create a small application. The nice thing about Backbone.js, is that we can create a whole app with just Views (DOM manipulation, events, etc...). So, excuse the hot design, but here is our lovely demo site.

We introduce the concept of region's. A region's, in this context, definition (stolen straight from Marionette.js):

Regions provide a consistent way to manage your views and show / close them in your application. They use a jQuery selector to show your views in the correct place.

We have two regions in our app; header and content. Our sidebar is simply HTML so no need to attach any functionality to it, however our header contains our menu links and our content needs to swap different Views in and out of itself.

In our Router's app.js file:

app.utils.viewManager.addRegion('content', '#jsRegion-content');
...
app.utils.viewManager.swap('header', new app.views.header());

The site uses HTML5's History API for pushState navigation and as you can see from the code, we use the app's Router file to swap in the relevant View instance into the content div.

In our Router's app.js file (we navigate the user to /about and then load up the "about" view):

about: function(){
	app.utils.viewManager.swap('content', new app.views.about());
}

Views are appropriately shut down and destroyed by our ViewManager. You'll also note the fact that all of our Views extend a Base View. This holds all the methods that we might want to be globally available to our Views. As you can see, because our app is just static HTML held in templates, we can let the Base View's render method take care of populating the View's element with the relevant View's template.

In about.js (our specific view):

template: $('#template-about').html()

In base.js:

render: function() {
    var template = Handlebars.compile(this.template);
    this.$el.html(template());
    return this;
}

As you can see, we have the makings of a scalable application using the ViewManager. This specific demo site only uses DOM manipulation, ie. it doesn't save or read data from a server. You could use this GitHub repo as a solid base for your next Backbone.js application, easily adding Models and extra functionality as needed, but the ViewManager will take most of your pain away when dealing with memory management and View lifecycle.

Caveats

This repo isn't a model for everything in Backbone.js, it doesn't deal with script tag management (hopefully you missed the 80 billion tags I included in index.html). We also aren't pre-compiling our Templates (we can use Grunt for this, for example), so we're missing out on a big performance win there. And it's obvious but I'll point it out, Backbone.js does leave a lot of the decisions for you to make, so every developer who deals with Backbone.js has a different take on it's use. This repo isn't gospel for Backbone.js development. Use it, modify it and then find a nice workflow for your style of development.

A small request

If anyone can figure out, when I'm using pushState, why I need to manually trigger the "home" route on initialisation and not just let the "routes" object take care of the initial routing:

Backbone.history.start({
	pushState: true,
	root: "/"
});
app.router.navigate('home', {
	trigger: true
}); 

I'll update this post with the solution (if anyone has it!).

As always, if anyone has any problems or queries with the post/it's code then feel free to tweet me or raise an issue on the GitHub repo and I'll do my bestest to help you out.

I'm available for hire

Hire me