May 11, 2012 | Chris Rock

Backbone.js — A Beginner’s Tutorial to Events

Backbone.js is a javascript framework that helps you write structured, easy-to-manage javascript–giving an valuable tool to web developers who are writing complicated javascript applications. Although it’s been compared to using an MVC framework, it’s not quite the same–the view plays the role of controller as well–dealing with events. There’s a lot to learn about Backbone.js, but in this tutorial we’re going to concentrate on how the View handles Events.

Demonstration – Executive Function Test

Your executive function is your ability for your brain to switch between different tasks. We be building a simple test similar to what psychologists and neuroscientists use to measure executive function. We create two fields and make either a red square or blue square appear in one of them. If it’s a red square, the user clicks on the field the square is in. If it’s a blue square, they click on the opposite field. We need to track the number of attempts and the number of correct choices. We also need a way to start and restart the test. You can view the complete demonstration of the executive function test here.

The Model

This example focuses on using the View, so the Model for this will be a simple repository for a handful of variables that we want easily accessible to the view.

var Model = Backbone.Model.extend({
    defaults: {
        score: 0,
        attempts: 0,
        currentLocation: 1,
        currentColor: 'red'
    }
});

The HTML

Backbone.js views have the power to dynamically create HTML and DOM elements using templates, but because we’re focusing on Events and we want to keep this example simple, we’ll just use some existing HTML. Here’s the relevant code.

<div class="controls">
    <ul>
        <!-- These will be changed dynamically by the program -->
        <li>Score: <span id="score">0</span></li>
        <li>Attempts: <span id="attempts">0</span></li>
        <li>Percentage: <span id="percentage">100%</span></li>
    </ul>
    <button id="start">Start Test</button><button id="reset">Reset Test</button>
</div>

The View

To start with, we create a View object, which we’ll call “Test”.

var Test = Backbone.View.extend({
    el: $('body'),
    model: new Model(), // See model above
 
    // .... future functions to go here .... //
});
var test = new Test();

The view itself will be created when we create an instance of it at the end with var test = new Test();. We attach the view to the ‘body’ tag which gives it access to the HTML that we created above. Then we create a new Model for it (an instance of the Model code we created above). Now, if we wanted information from the Model within the view–for example, the score–we simply use this.model.get('score');. We can set data by using something like this.model.set('score', 2);.

Events

Here’s an example of how the view in Backbone.js plays the role of the controller in a traditional MVC structure. We define events that can happen within the view here:

var Test = Backbone.View.extend({
    // ... Setup code (see above) ... //
 
    events: {
        'click button#start' : 'start',
        'click .field' : 'score',
        'click button#reset' : 'reset'
    },
    // Event handling functions (details below)
    start: function() { ... },
    score: function(event) { ... },
    reset: function() { ... },
 
    // ... additional functions here ... //
});

Each event describes the event, the selector to listen to, and the callback function. In the case of the first event, the button element with the start id is listening for a click event. When it gets that event, it runs the start function located in the view. This and all future function example are contained within the Test view, although that’s not expressly shown.

Start Event

start: function() {
    this.addRandomSpriteToField();
}

The function is really simple–it just calls another function :) The function it calls is a little more complicated. The inline comments explain what it does.

addRandomSpriteToField: function() {
    // Pick random field
    var randomField = Math.floor(Math.random() * 2) + 1;
    // Pick a random color
    var randomColor = Math.floor(Math.random() * 2) + 1;
    color = (randomColor == 1) ? 'red' : 'blue';
    // Pick a random location
    var x = $('.field').width() - 100;
    var y = $('.field').height() - 100;
    var randomX = Math.floor(Math.random() * x) + 1;
    var randomY = Math.floor(Math.random() * y) + 1;
    // Create a sprite with chosen attributes
    var sprite = $('<div class="sprite"> </div>').css({
        'background-color' : color,
        'left' : randomX + 'px',
        'top' : randomY + 'px'
    });
    // Erase fields and add sprite to chosen field
    $('.field').empty();
    $('.field-' + randomField).append(sprite);
    // Update model data
    this.model.set('currentLocation', randomField);
    this.model.set('currentColor', color);
}

Notice that we’re using the jQuery/Zepto $(selector) functionality to manipulate the DOM. Backbone.js doesn’t include it natively so be sure to include it in your scripts.

Click a Field Event

The next event is bound to both the fields. Whenever they’re clicked they call the score function.

score: function(event) {
    // Get the id of the clicked field
    var fieldId = event.target.getAttribute('data-id');
    if(
        ( // Red square same field
            this.model.get('currentLocation') == fieldId &&
            this.model.get('currentColor') == 'red'
        ) ||
        ( // Blue square opposite field
            this.model.get('currentLocation') != fieldId &&
            this.model.get('currentColor') == 'blue'
        )
    ) {
        this.model.set('score', this.model.get('score') + 1);
    }
    this.model.set('attempts', this.model.get('attempts') + 1);
    this.addRandomSpriteToField();
    this.setScore();
},

Because this event could be triggers from one of two different fields, we need to know which one was clicked. Here we use event.target.getAttribute('data-id'). Then we check to see if the user did the correct action–same field if it’s a red square, opposite field if it’s a blue square. If they did, we add the score to the model. Whether they got the right score or not, we add increase the number of attempts. Then we add a new sprite using the addRandomSpriteToField function we’ve already seen. Then we call the setScore function, which updates the DOM with the new score data:

setScore: function() {
    $('#score').text(this.model.get('score'));
    $('#attempts').text(this.model.get('attempts'));
    if(this.model.get('attempts') != 0) { // Avoid a divide by 0 error
        $('#percentage').text(Math.floor((this.model.get('score') / this.model.get('attempts')) * 100) + '%')
    } else {
        $('#percentage').text('100%');
    }
},

Restart Event

The next event is the restart, which is bound to the “Reset Test” button and calls the reset function.

reset: function() {
    // Erase the fields
    $('.field').empty();
    // Reset the data
    this.model.set('score', 0);
    this.model.set('attempts', 0);
    // Reset DOM elements
    this.setScore();
},

At the end, we update the DOM with the setScore we’ve seen already.

So we can see how in Backbone.js, the Events and controlled and managed by the View. If we were using just jQuery to do this, it would be a mess of events bound to DOM elements that would have difficulty communicating with each other. Using Backbone.js, we were able to easily extract reused code into separate functions (setScore and addRandomSpriteToField). Using Backbone.js also allowed us to have an easily accessible source of data. All in all, using Backbone.js give the code better, cleaner structure and makes it easy to create and make future additions or edits.

  • Development
  • backbone
  • javascript
  • jquery