A quick glance at Backbone.js: Todo MVC

I had been on and off with Backbone for some time but had finally come around to getting somewhat of an understanding of the basics of how Backbone is organized and how it can help with your JavaScript-robust applications. I’ve read numerous tutorials and hadn’t quite gotten the picture. They were either outdated, too bloated, or not enough. I’ll attempt at helping to clarify the basics in this tutorial and perhaps write more advanced topics later.

Some immediate things-to-consider from my approach sofar:

  • I’m not using require.js, which I know a lot of front-enders depend on
  • I’m relying on Yeoman’s Backbone Generator which saves an enormous amount of leg work for getting the structure of your application ready. If you haven’t tried Yeoman yet, give it a go. It’s super great for getting projects off the ground.
  • Basically, what got me to this point was a combination of reading Addy Osmani’s Backbone tutorials and this tutorial which uses Yeoman to speed up the process.

Let’s dive in. First, we’ll look at our main.js file.

The init method immediately calls upon a view from our Todos colllection. In views/todos-view.js, our view defines most of the logic for interacting with our app, but we will frequently call on various methods defined in the Collection that it renders.

(function(){
    
    'use strict';
    
    window.backboneApp = {
        Models: {},
        Collections: {},
        Views: {},
        Routers: {},
        init: function () {
            console.log('Hello from Backbone!');
            new this.Views.TodosView({
                collection: new this.Collections.TodosCollection()
            });
        }
    };

    $(document).ready(function () {
        backboneApp.init();
    });
})();

For example, after completing the bare necessities of a Todo app, I wanted to add a Clean button that will clear all checked off items on the Todo Collection.

We’ll start by modifying our todos.ejs template and adding a ‘Clean’ button.


<form class="input-append">
<input id="new-todo" type="text" placeholder="What do you need to do today?" /> 
<input class="btn" type="submit" value="Submit" />
</form>

<form class="filter"><input id="clear-completed" class="btn" type="button" value="Clean" /></form>
<ul><!-- Where our To Do items will go --></ul>

We’ll now jump to our parent view, todos-view.js and add an event listener for our Clean button:


events: {
    'click #clear-completed': 'clearCompleted'
},

// Clear all completed todo items, destroying their models
clearCompleted: function() {
    _.invoke(this.collection.completed(), 'destroy');
    return false;
}

The clearCompleted method uses Underscore’s invoke method to get a list of the completed items and then use Backbone’s native destroy method to not only remove them from the view, but delete their models as well. The list of completed items is obtained from the collection’s completed method:


backboneApp.Collections.TodosCollection = Backbone.Collection.extend({
    
    completed: function() {
      return this.filter(function(todo){
        return todo.get('completed');
      });
    }

});

We’re using Backbone’s other native method, get, to obtain a list of models that have the completed attribute. Opening our todo-model.js file, we see that our model defaults to ‘false’. The ‘toggle’ method toggles this attribute. Backbone keeps track of these ‘states’ for each model.


(function(){
    
    'use strict';

    backboneApp.Models.TodoModel = Backbone.Model.extend({

        defaults: {
            title: '',
            completed: false
        },
        
        toggle: function() {
            this.save({
                completed: !this.get('completed')
            });
        }
    });

})();