Backbone.js Tips And Patterns

Advertisement

Backbone.js is a popular open-source JavaScript “MV*” framework that has gained significant traction since its first release a little over three years ago. Although Backbone.js provides structure to JavaScript applications, it leaves a lot of design patterns and decisions up to the developer, for better or worse, and developers run into many common problems when they first begin developing in Backbone.js.

Therefore, in this article, we’ll explore different design patterns that you can use in your Backbone.js applications, and we’ll look at many of the common gotchas that trip up developers.

Austin, Texas in autumn
Applications, like buildings, are best built following known patterns. (Image: Matthew Rutledge)

Perform Deep Copies Of Objects

JavaScript treats all primitive-type variables as pass-by-value. So, the value of a variable is passed when the variable is referenced.

var helloWorld = “Hello World”;
var helloWorldCopy = helloWorld;

For example, the code above will set helloWorldCopy equal to the value of helloWorld. So, any modification to helloWorldCopy will not modify helloWorld, since it is a copy. JavaScript treats all non-primitive type variables as pass-by-reference, meaning that JavaScript will pass a reference of the memory address of the variable when the variable is referenced.

var helloWorld = {
    ‘hello’: ‘world’
}
var helloWorldCopy = helloWorld;

For example, the code above will set helloWorldCopy equal to the reference of helloWorld, and, as you might guess, any modifications to helloWorldCopy would directly manipulate helloWorld. If you’d like to have a copy of the helloWorld, you will have to create a copy of the object.

You’re probably wondering, “Why is he explaining all of this pass-by-reference stuff?” Well, Backbone.js does not copy objects, which means that if you .get() an object from a model, any modifications to that object will directly manipulate the object! Let’s look at an example to illustrate where this can become an issue. Let’s say you have a Person model like the following:

var Person = Backbone.Model.extend({
   defaults: {
        'name': 'John Doe',
        'address': {
            'street': '1st Street'
            'city': 'Austin',
            'state': 'TX'
            'zipCode': 78701
        }
   }
});

And let’s say you create a new person object:

var person = new Person({
    'name': 'Phillip W'
});

Now, let’s manipulate some of the attributes of the new person object:

person.set('name', 'Phillip W.', { validate: true });

The code above successfully manipulates the name attribute of the person object. Now let’s try to manipulate the address of the person object. However, before doing so, let’s add some validation for the address.

var Person = Backbone.Model.extend({
    validate: function(attributes) {

        if(isNaN(attributes.address.zipCode)) return "Address ZIP code must be a number!";
    },

    defaults: {
        'name': 'John Doe',
        'address': {
            'street': '1st Street'
            'city': 'Austin',
            'state': 'TX'
            'zipCode': 78701
        }
    }
});

Now, let’s attempt to manipulate the address with an incorrect ZIP code.

var address = person.get('address');
address.zipCode = 'Hello World';
// Raises an error since the ZIP code is invalid
person.set('address', address, { validate: true });
console.log(person.get('address'));
/* Prints an object with these properties.
{
    'street': '1st Street'
    'city': 'Austin',
    'state': 'TX'
    'zipCode': 'Hello World'
}
*/

How can this be? Our validation has raised an error! Why are the attributes still changed? As mentioned, Backbone.js does not copy model attributes; it simply returns whatever you’re asking for. So, as you might guess, if you ask for an object, you will get a reference to that object, and any manipulation to the object will directly manipulate the actual object in the model. This can quickly lead you down a very dark rabbit hole that can take you hours of debugging to diagnose.

Rabbit hole
Performing a deep copy of model objects can save you from going down a rabbit hole of debugging. (Image: David Orban)

This issue catches developers who are new to Backbone.js and even seasoned JavaScript developers off guard. This issue has been heavily discussed in the GitHub issues section of Backbone.js. As Jeremy Ashkenas points out there, performing a deep copy is a very difficult problem to solve, and it can become an expensive operation for very large, deep objects.

Luckily, jQuery provides an implementation of deep copying, $.extend. As an aside, Underscore.js, a dependency of Backbone.js, provides the _.extend function, but I would avoid using it because it does not perform a deep copy. Lo-Dash, a forked and optimized version of Underscore.js, provides a _.clone function with the option to perform a deep copy. However, I use $.extend to perform a deep copy of any object that I .get() from a model using the following syntax. Remember to pass true, so that it performs a deep copy of the object.

var address = $.extend(true, {}, person.address);

We now have an exact copy of the address object, and we can modify it to our heart’s content without worrying about modifying the actual model. You should be aware that this pattern works for the above example because all of the members of the address object are immutable(numbers, strings, etc.), and that while the above example works you should use caution when deep copying objects that contain objects. You should also know that there is a small performance hit from performing a deep copy, but I have never seen this cause noticeable problems. However, if you’re deep copying massive objects, or thousands of objects all at once, you’ll likely want to do some performance profiling. This leads us directly to the next pattern.

Create Facades To Objects

In the real world, requirements change often, and so does the JavaScript Object Notation (or JSON) returned by the endpoints that your models and collections hit. This can become a really big pain point in your code base if your view is tightly coupled to the underlying data model. Therefore, I create getters and setters for all objects.

The pros of this pattern are many. If any of the underlying data structures change, then the view layers shouldn’t have to update that much; you will have one point of access to the data, so you are less likely to forget to do a deep copy, and your code will be more maintainable and much easier to debug. The downside is that this pattern can cause a bit of bloat in your models or collections.

Let’s look at an example to illustrate this pattern. Imagine we have a Hotel model that contains rooms and the currently available rooms, and that we want to be able to retrieve rooms by bed size.

var Hotel = Backbone.Model.extend({
    defaults: {
        "availableRooms": ["a"],
        "rooms": {
            "a": {
                "size": 1200,
                "bed": "queen"
            },
            "b": {
                "size": 900,
                "bed": "twin"
            },
            "c": {
                "size": 1100,
                "bed": "twin"
            }
        },

        getRooms: function() {
            $.extend(true, {}, this.get("rooms"));
        },

        getRoomsByBed: function(bed) {
            return _.where(this.getRooms(), { "bed": bed });
        }
    }
});

Now let’s imagine that tomorrow you will be releasing your code, and you find out that the endpoint developers forgot to tell you that the data structure of rooms has changed from an object to an array. Your code now looks like the following.

var Hotel = Backbone.Model.extend({
    defaults: {
        "availableRooms": ["a"],
        "rooms": [
            {
                "name": "a",
                "size": 1200,
                "bed": "queen"
            },
            {
                "name": "b",
                "size": 900,
                "bed": "twin"
            },
            {
                "name": "c",
                "size": 1100,
                "bed": "twin"
            }
        ],

        getRooms: function() {
            var rooms = $.extend(true, {}, this.get("rooms")),
             newRooms = {};

            // transform rooms from an array back into an object
            _.each(rooms, function(room) {
                newRooms[room.name] = {
                    "size": room.size,
                    "bed": room.bed
                }
            });
        },

        getRoomsByBed: function(bed) {
            return _.where(this.getRooms(), { "bed": bed });
        }
    }
});

We updated only one function in order to transform the Hotel structure into the structure that the rest of our application expects, and our entire app still behaves as expected. If we didn’t have a getter here, we might potentially have to update each point of access to rooms. Ideally, you would want to update all of your functions to work with the new data structure, but if you’re pressed for time and have to release, this pattern can save you.

As an aside, this pattern can be thought of as both a facade design pattern, because it hides the complexity of creating a copy of your objects, or a bridge design pattern, because it can be used to transform data into what is expected. A good rule of thumb is to use getters and setters on anything that is an object.

Store Data Not Persisted By The Server

Although Backbone.js prescribes that models and collections map to representational state transfer (or REST-ful) endpoints, you will sometimes find that you want to store data in your models or collections that is not persisted on the server. Many other articles about Backbone.js, such as “Backbone.js Tips: Lessons From the Trenches” by Prateek Dayal of SupportBee, describe this pattern. Let’s look at a quick example to help explain where this might come in handy. Suppose you have a ul list.

<ul>
	<li><a href="#" data-id="1">One</a></li>
	<li><a href="#" data-id="2">Two</a></li>
    . . .
	<li><a href="#" data-id="n">n</a></li>
</ul>

Where n is 200 and when the user clicks on one of the items, that item becomes selected and is visualized to the user as the chosen item by a selected class being added. One approach to this would be the following:

var Model = Backbone.Model.extend({
    defaults: {
        items: [
            {
                "name": "One",
                "id": 1
            },
            {
                "name": "Two",
                "id": 2
            },
            {
                "name": "Three",
                "id": 3
            }
        ]
    }
});

var View = Backbone.View.extend({
    template: _.template($('#list-template').html()),

    events: {
        "#items li a": "setSelectedItem"
    },

    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
    },

    setSelectedItem: function(event) {
        var selectedItem = $(event.currentTarget);
        // Set all of the items to not have the selected class
        $('#items li a').removeClass('selected');
        selectedItem.addClass('selected');
        return false;
    }
});
<script id="list-template" type="template">
<ul id="items">
        <% for(i = items.length - 1; i >= 0; i--) { %>
	<li>
                <a href="#" data-id="<%= item[i].id %>"><%= item[i].name %></a></li>
<% } %></ul>
</script>

Now let’s say we want to figure out which item has been selected. One way would be to traverse the list. But if the list is really long, this could become quite an expensive task. Therefore, let’s also store which item is selected when the user clicks on a list item.

var View = Backbone.View.extend({
    initialize: function(options) {
        // Re-render when the model changes
        this.model.on('change:items', this.render, this);
    },

    template: _.template($('#list-template').html()),

    events: {
        "#items li a": "setSelectedItem"
    },

    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
    },

    setSelectedItem: function(event) {
        var selectedItem = $(event.currentTarget);
        // Set all of the items to not have the selected class
        $('#items li a').removeClass('selected');
        selectedItem.addClass('selected');
        // Store a reference to what item was selected
        this.selectedItemId = selectedItem.data('id'));
        return false;
    }
});

Now we can now easily determine which item has been selected, and we don’t have to traverse the Document Object Model (DOM). This pattern is extremely useful for storing extraneous data that you might want to keep track of; keep in mind also that you can create models and collections that don’t necessarily have endpoints associated with them to store extraneous view data.

The downsides to this pattern are that if you store extraneous data in your models or collections, they won’t really follow a RESTful architecture since they won’t map perfectly to a Web resource; also, this pattern can cause a bit of bloat in your objects; and it can cause a bit of pain when saving your models if your endpoint strictly accepts only the JSON it expects.

You may be asking yourself, “How do I determine if I should put the extra data in the view or the model?”. If the extra attributes you’re adding are centered around rendering, such as the height of a container, they should probably be added to the view. If the attributes have anything to do with the underlying data model, then you may want to push that into the model. For example, if the above example were more flushed out and for some reason I only wanted users to be able to select a specific range of items from the list of items returned by the model, I would likely push that logic into the model. In short, as most things go, it really depends on the situation. You can argue for keeping your models truly faithful to REST and you can argue that you should keep your views as dumb as possible and push as much logic into your models.

Render Parts Of Views Instead Of Entire Views

When you first begin developing Backbone.js applications, your views will typically be structured something like this:

var View = Backbone.View.extend({
    initialize: function(options) {
        this.model.on('change', this.render, this);
    },

    template: _.template($(‘#template’).html()),

    render: function() {
        this.$el.html(template(this.model.toJSON());
        $(‘#a’, this.$el).html(this.model.get(‘a’));
        $(‘#b’, this.$el).html(this.model.get(‘b’));
    }
});

Here, any change to your model will trigger a complete re-rendering of the view. I was a practitioner of this pattern when I first began developing with Backbone.js. But as my view code grew in size, I quickly realized that this approach was not maintainable or optimal because the view was being completely re-rendered when any attribute of the model changed.

When I ran into this problem, I did a quick Google search to see what others had done and found Ian Storm Taylor’s blog post, “Break Apart Your Backbone.js Render Methods,” in which he describes listening for individual attribute changes in the model and then re-rendering only the part of the view corresponding to the changed attribute. Taylor also describes returning a reference to the object so that the individual rendering functions can be easily chained together. The example above now transforms into something much more maintainable and performant because we are only updating portions of the view that correspond to the model attributes that have changed.

var View = Backbone.View.extend({
    initialize: function(options) {
        this.model.on('change:a', this.renderA, this);
        this.model.on('change:b', this.renderB, this);
    },

    renderA: function() {
        $(‘#a’, this.$el).html(this.model.get(‘a’));
        return this;
    },

    renderB: function() {
        $(‘#b’, this.$el).html(this.model.get(‘b’));
        return this;
    },

    render: function() {
        this
            .renderA()
            .renderB();
    }
});

I should mention that many plugins, such as Backbone.StickIt and Backbone.ModelBinder, provide key-value bindings between model attributes and view elements, which can save you from a lot of boilerplate code. So, check them out if you have complex form fields.

Keep Models Agnostic To Views

As Jeremy Ashkenas points out in one of Backbone.js’ GitHub issues, Backbone.js doesn’t enforce any real separation of concerns between the data and view layer, except that models are not created with a reference to their view. Because Backbone.js doesn’t enforce a separation of concerns, should you? I and many other Backbone.js developers, such as Oz Katz and Dayal, believe the answer is overwhelmingly yes: Models and collections, the data layer, should be entirely agnostic of the views that are bound to them, keeping a clear separation of concerns. If you don’t follow a separation of concerns, your code base could quickly turn into spaghetti code, and no one likes spaghetti code.

Spaghetti.
Keeping your models agnostic to your views will help prevent spaghetti code, and no one likes spaghetti code! (Image: Sira Hanchana)

Keeping your data layer completely agnostic to the view layer allows for a more modular, reusable and maintainable code base. You can easily reuse and extend models and collections throughout your application without concern for the views that are tying into them. Following this pattern enables developers who are new to your project to quickly dive into the code base, because they will know exactly where rendering takes place and where all of the business logic of your application should live.

This pattern also enforces the single responsibility principle, which dictates that each class should have a single responsibility, and its responsibility should be encapsulated in the class, since your models and collections should handle data and your views should handle rendering.

Parameter Mapping In Routers

The best way to demonstrate how this pattern came about is through an example. Let’s say you have some sort of search page, and that the search page allows users to add two different filter types, foo and bar, each of which has a multitude of options. Therefore, your URL structure would start off looking something like this:

'search/:foo'
'search/:bar'
'search/:foo/:bar'

Now, all of these routes use the exact same view and model, so you would ideally like them all to use the same function, search(). However, if you examine Backbone.js, there isn’t any sort of parameter mapping; the parameters are just plopped into the function from left to right. So, in order for them all to use the same function, you would end up creating different functions to correctly map the parameters to search().

routes: {
    'search/:foo': 'searchFoo',
    'search/:bar': 'searchBar',
    'search/:foo/:bar': 'search'
},

search: function(foo, bar) {
},

// I know this function will actually still map correctly, but for explanatory purposes, it's left in.
searchFoo: function(foo) {
    this.search(foo, undefined);
},

searchBar: function(bar) {
    this.search(undefined, bar);
},

As you can imagine, this pattern could quickly bloat your routers. When I first ran into this problem, I attempted to do some parsing of the actual function definitions with regular expressions to “magically” map the parameters, which would have worked — but only if I had followed specific constraints. So, I scrapped the idea (I might still throw this into a Backbone plugin sometime). I opened an issue on GitHub, and Ashkenas suggested mapping all of the parameters in the search function.

The code above now transforms into something much more maintainable:

routes: {
    'base/:foo': 'search',
    'base/:bar': 'search',
    'base/:foo/:bar': 'search'
},

search: function() {
    var foo, bar, i;

    for(i = arguments.length - 1; i >= 0; i--) {

        if(arguments[i] === 'something to determine foo') {
            foo = arguments[i];
            continue;
        }
        else if(arguments[i] === 'something to determine bar') {
            bar = arguments[i];
            continue;
        }
    }
},

This pattern can drastically reduce router bloat. However, be aware that it will not work for parameters that are not distinguishable. For example, if you had two parameters that were both IDs and followed the pattern XXXX-XXXX, you would not be able to identify which ID corresponded to which parameter.

model.fetch() Won’t Clear Your Model

This usually trips up those who are new to Backbone.js: model.fetch() will not clear out your model, but rather extends the attributes of your model. Therefore, if your model has attributes x, y and z and your fetch returns y and z, then x will still be in the model and only y and z will be updated. The following example visualizes this concept.

var Model = Backbone.Model.extend({
    defaults: {
        x: 1,
        y: 1,
        z: 1
    }
});
var model = new Model();
/* model.attributes yields
{
    x: 1,
    y: 1,
    z: 1
} */
model.fetch();
/* let’s assume that the endpoint returns this
{
    y: 2,
    z: 2,
} */
/* model.attributes now yields
{
    x: 1,
    y: 2,
    z: 2
} */

PUTs Require An ID Attribute

This one also usually trips up those who are new to Backbone.js. To have your models send a HTTP PUT request when you call .save(), your model is required to have an ID attribute set. Remember that the HTTP PUT verb is designed to be an update, so it makes sense that to send a PUT request, your model is required to have an ID. In an ideal world, all of your models would have a perfect ID attribute named ID, but the JSON data that you receive from your endpoints will likely not always have perfectly named IDs.

Therefore, if you need to update a model, be sure that an ID is on the model before saving it. Backbone.js versions 0.5 and greater allow you to change the name of the ID attribute of your models using idAttribute, in case your endpoint doesn’t return IDs named id.

If are stuck using a version of Backbone.js lower than 0.5, I suggest that you modify the parse function of your collection or model to map your expected ID attribute to the attribute ID. Here’s a quick example of how you can achieve this by modifying your parse function. Let’s imagine you have a collection of cars whose IDs are carID.

parse: function(response) {

    _.each(response.cars, function(car, i) {
        // map the returned ID of carID to the correct attribute ID
        response.cars[i].id = response.cars[i].carID;
    });

    return response;
},

Model Data On Page Load

Sometimes you will find that your models or collections need to be initialized with data on page load. Many articles about Backbone.js patterns, such as Rico Sta Cruz’ “Backbone Patterns” and Katz’ “Avoiding Common Backbone.js Pitfalls,” discuss this pattern. This pattern is easily achieved by inlining a script on the page and rendering out the data in either single-model attributes or JSON, using the server-side language of your choice. For example, in Rails, I use one of the following:

// a single attribute
var model = new Model({
    hello: 
});
// or to have json
var model = new Model();

Using this pattern could improve your search engine rankings by “instantly” rendering out your page, and it could drastically shorten the time it takes for your application to be up and running by limiting the application’s initial HTTP requests.

Handling Failed Model Attribute Validation

Very often, you will want to know what model attributes have failed validation. For example, if you have an extremely complex form field, you might want to know which model attribute has failed validation so that you can highlight the input field corresponding to the attribute. Unfortunately, alerting your views as to which model attributes have failed validation is not directly baked into Backbone.js, but you can use a few different pattern to handle this.

Return an Error Object

One pattern to notify your views of which model attributes have failed validation is to pass back an object with some sort of flag detailing which attribute has failed validation, such as the following:

// Inside your model
validate: function(attrs) {
    var errors = [];

    if(attrs.a < 0) {
        errors.push({
            'message': 'Form field a is messed up!',
            'class': 'a'
        });
    }
    if(attrs.b < 0) {
        errors.push({
            'message': 'Form field b is messed up!',
            'class': 'b'
        });
    }

    if(errors.length) {
        return errors;
    }
}
// Inside your view
this.model.on('invalid’, function(model, errors) {
    _.each(errors, function(error, i) {
        $(‘.’ + error.class).addClass('error');
        alert(error.message);
    });
});

The advantage of this pattern is that you are handling all invalid messages in one location. The disadvantage is that your invalid method could become a large switch or if statement if you deal with invalid attributes differently.

Broadcast Custom Error Event

An alternative pattern, suggested by a friend of mine, Derick Bailey, is to trigger custom errors events for each model attribute. This allows your views to bind to specific error events for individual attributes:

// Inside your model
validate: function(attrs) {

    if(attrs.a < 0) {
            this.trigger(‘invalid:a’, 'Form field a is messed up!', this);
    }
    if(attrs.b < 0) {
            this.trigger(‘invalid:b’, 'Form field b is messed up!', this);
    }
}
// Inside your view
this.model.on('invalid:a’, function(error) {
        $(‘a’).addClass('error');
        alert(error);
});
this.model.on('invalid:b’, function(error) {
        $(‘b’).addClass('error');
        alert(error);
});

The advantage of this pattern is that your view bindings are explicit in the type of error they are bound to, and if you have specific instructions for each type of attribute error, it can clean up your view code and make it more maintainable. The one downside of this pattern is that your views could become rather bloated if there aren’t many differences in how you handle different attribute errors.

Both patterns have their pros and cons, and you should think about which pattern is best for your use case. If you treat all failed validation errors the same way, then the first approach would probably be best; if you have specific UI changes per model attribute, then the latter approach would be better.

HTTP Status Code 200 Trigger Error

If the endpoint that your model or collection is hitting returns invalid JSON, then your model or collection will trigger an “error” event, even if the endpoint returns a 200 HTTP status code. This issue mostly comes up when developing locally against mock JSON data. So, a good rule of thumb is to throw any mock JSON files you’re developing through a JSON validator. Or get a plugin for your IDE that will catch any ill-formatted JSON.

Create A Generic Error Display

This one could save you time and create a uniform pattern for handling and visualizing error messages, which will improve your user’s overall experience. In any Backbone.js app that I develop, I create a generic view that handles alerts:

var AlertView = Backbone.View.extend({
    set: function(typeOfError, message) {
        var alert = $(‘.in-page-alert’).length ? $(‘.in-page-alert’): $(‘.body-alert’);
        alert
            .removeClass(‘error success warning’)
            .addClass(typeOfError)
            .html(message)
            .fadeIn()
            .delay(5000)
            .fadeOut();
    }
});

The view above first looks to see whether there is a view-specific in-page-alert div, which you would declare inside of your view’s markup. If there is no view-specific div, then it falls back to a generic body-alert div, which you would declare somewhere in the layout. This enables you to deliver a consistent error message to your users and provides a useful fallback in case you forget to specify a view-specific in-page-alert div. The pattern above streamlines how you handle error messages in your views, as follows:

var alert = new AlertView();

this.model.on('error', function(model, error) {
    alert.set('TYPE-OF-ERROR', error);
});

Update Single-Page App Document Titles

This is more of a usability concern than anything. If you’re developing a single-page application, remember to update the document title of each page! I’ve written a simple Backbone.js plugin, Backbone.js Router Title Helper, that does this in a simple and elegant format by extending the Backbone.js router. It allows you to specify a title’s object literal, whose keys map to route function names and whose values are page titles.

Backbone.Router = Backbone.Router.extend({

    initialize: function(options){
        var that = this;

        this.on('route', function(router, route, params) {

            if(that.titles) {
                if(that.titles[router]) document.title = that.titles[router];
                else if(that.titles.default) document.title = that.titles.default;
                else throw 'Backbone.js Router Title Helper: No title found for route:' + router + ' and no default route specified.';
            }
        });
    }
});

Cache Objects In Single-Page Applications

While we are on the topic of single-page applications, another pattern you could follow is to cache objects that will be reused! This case is fairly straightforward and simple:

// Inside a router
initialize: function() {

    this.cached = {
        view: undefined,
        model: undefined
    }
},

index: function(parameter) {
    this.cached.model = this.cached.model || new Model({
        parameter: parameter
    });
    this.cached.view = this.cached.view || new View({
        model: this.cached.model
    });
}

This pattern will give your application a small bump in speed because you won’t have to reinitialize your Backbone.js objects. However, it could cause your application’s memory footprint to grow rather large; so, I’ll typically only cache objects that are commonly used throughout an application. If you’ve developed Backbone.js apps in the past, then you’re likely asking yourself, “What if I want to refetch data?” You can refetch data each time the route is triggered:

// Inside a router
initialize: function() {

    this.cached = {
        view: undefined,
        model: undefined
    }
},

index: function(parameter) {
    this.cached.model = this.cached.model || new Model({
        parameter: parameter
    });
    this.cached.view = this.cached.view || new View({
        model: this.cached.model
    });
    this.cached.model.fetch();
}

This pattern will work when your application must retrieve the latest data from the endpoint (for example, an inbox). However, if the data that you’re fetching is dependent on the state of the application (assuming that the state is maintained through your URL and parameters), then you would be refetching data even if the application’s state hasn’t changed since the user was last on the page. A better solution would be to refetch data only when the state of the application (parameter) has changed:

// Inside a router
initialize: function() {

    this.cached = {
        view: undefined,
        model: undefined
    }
},

index: function(parameter) {
    this.cached.model = this.cached.model || new Model({
        parameter:parameter
    });
    this.cached.model.set('parameter', parameter);
    this.cached.view = this.cached.view || new View({
        model: this.cached.model
    });
}

// Inside of the model
initialize: function() {
    this.on("change:parameter", this.fetchData, this);
}

JSDoc Functions And Backbone.js Classes

I’m a huge fan of documentation and JSDoc. I JSDoc all Backbone classes and functions in the following format:

var Thing = Backbone.View.extend(/** @lends Thing.prototype */{
    /** @class Thing
     * @author Phillip Whisenhunt
     * @augments Backbone.View
     * @contructs Thing object */
    initialize() {},

    /** Gets data by ID from the thing. If the thing doesn't have data based on the ID, an empty string is returned.
     * @param {String} id The id of get data for.
     * @return {String} The data. */
    getDataById: function(id) {}
});

If you document your Backbone classes in the format above, then you can generate beautiful documentation that contains all of your classes and functions with parameters, return types and descriptions. Be sure to keep the initialize function as the first function declared, which helps when generating JSDoc. If you’d like to see an example of a project that uses JSDoc, check out the HomeAway Calendar Widget. There is also a Grunt.js plugin, grunt-jsdoc-plugin, to generate documentation as part of your build process.

Practice Test-Driven Development

In my opinion, if you’re writing in Backbone.js, you should be following test-driven development (TDD) for your models and collections. I follow TDD by first writing failing Jasmine.js unit tests against my models or collections. Once the unit tests are written and failing, I flush out the model or collection.

By this point, all of my Jasmine tests will have been passing, and I have confidence that my model functions all work as expected. Since I’ve been following TDD, my view layer has been super-easy to write and also extremely thin. When you begin practicing TDD, you will definitely slow down; but once you wrap your head around it, your productivity and the quality of your code will dramatically increase.

I hope these tips and patterns have helped! If you have suggestions for other patterns or you’ve found a typo or you think that one of these patterns isn’t the best approach, please leave a comment below or tweet me.

Thanks to Patrick Lewis, Addy Osmani, Derick Bailey and Ian Storm Taylor for reviewing this article.

(al) (ea)

↑ Back to top

Phillip Whisenhunt is a Software Engineer and Entrepreneur living and playing in beautiful Austin, TX where he is building high performant front-ends. He's worked in a number of different areas, from Biometrics research to visualizing Genomes over the Web. You can follow him on twitter or read his blog.

  1. 1

    A while ago backbone was an interresting option, and I would have considered investing time to learn it, but the tracktion gained by backbone has since significantly shifted to angular js.

    0
    • 2

      I’ve worked with both, backbone and angular js on large web-apps, although angular makes building things pretty fast and in some cases very easy, it’s far from perfect and performance is definitely an issue I’ve encountered. I would recommend looking at ember js if you want to go down that kind of framework route; it’s the next framework I personally will be investing time in learning.

      0
    • 3

      Angular can keep some of it’s less-wise opinions. I prefer to hold my own with backbone, lo-dash and marionette built using Yeoman.

      0
    • 4

      Backbone requires a lot more setup but if you have created your framework from it, it is better than the other offerings in my opinion. I have grunt builds, servers, optimisations, two way binding, DOM manipulation, fastclick, mustache templating, packages, modules, controllers, layouts, child views, oauth, internationalization, and more in 120kb minified (not gzipped) and exactly how I want.

      0
    • 5

      By all means continue using Angular. It’s an awesome framework. But if you’re doing it, solely based on what’s popular, then you’re in for a rude awakening. Invest time before implementing a framework to ensure you’re using what’s right for that project. The two are very different.

      0
  2. 6

    Javascript passes everything by reference, some values such as strings and numbers look like they are passed by value because they are immutable (If you can’t modify an object, you can’t differentiate it from a copy, except for its identity, which is not visible in Javascript).
    You can read about it in pages 85/35/52 of the ECMAScript reference. (However at the implementation level, optimizing interpreters will probably pass immutable and small-enough primitive values by value).

    0
    • 7

      Technically, JS passes references by value. There is a difference. In a pass-by-reference language, the following would modify `x`, but in JavaScript, the reference to `x` is passed by value. Therefore, modifying the copy of the reference doesn’t modify the `x`.

      var x = {some: “key”}

      (function(inner_x){
      inner_x = {some: “new value”};
      })(x)

      x //=> {some: “key”}

      0
      • 8

        Sorry but again you’re wrong. I mean your demonstration is correct, but all pass by reference languages (Java, Python, Ruby, C#) behave like that.

        Call by reference mean that you receive a reference to the original object, not the original reference.

        IHMO you should update the first part of your article because it’s highly misleading for beginners. I personally stopped reading the article at that point.

        0
        • 9

          Chris Mountford

          April 5, 2014 5:52 pm

          Java and JavaScript and many other languages pass by value. What they are passing, however are references.

          If you read the specifications for these languages you will see this is so. Both Java and JavaScript treat primitives and “reference types” exactly the same when forming stack frames and you can see it in the implementations. In the case of Java you can also see it in the bytecode.

          The traditional distinction between pass by value and pass by reference was made for languages that have pointer arithmetic and dereference operators like C and C++, but it is not helpful to carry this context to JavaScript and Java etc. If such features were present in those languages, the proof that all calls are pass by value would be obvious.

          If you were to dereference an object argument passed to a function you would see that it is the same memory pointer as at the call site. This is the literal definition of pass by value.

          0
      • 10

        That’s correct, but in order to avoid confusion, it should also be noted that:

        var x = {some: “key”}

        (function(inner_x){
        inner_x.some = “new value”;
        })(x)

        x //=> {some: “new value”}

        0
      • 11

        That is totally wrong.

        You are not modifying the “copy”. As retrieved from argument, inner_x points at x, BUT, once you step into inner_x = { some: “new value” } JavaScript creates a new Object { some : “new value” }, then assigns a pointer at that newly created object to inner_x. Hence, original x is not overrided. What Leonardo mentions is exactly the case! You are referenced by value to a “simple-type” vars (string, numeric types, boolean, etc.) and by pointer to any other type (Object, Array, etc.)

        0
  3. 12

    Interesting stuff! Code review: In your #Create Facades To Objects# section, should `getRooms` not return something?

    0
  4. 14

    This is NOT a deep copy:

    var address = $.extend(true, {}, person.address);

    It’s only a deep copy if you assume that all the members of address are immutable (strings and numbers basically), this assumption is correct in the example given, but can very easily not be.

    This is why deep copying is a bigger problem, solving it in the obvious way (traversing the entire tree of objects) works. But if you don’t understand what’s going on, it can be an unexpectedly expensive operation.

    It’s better to educate people on how JavaScript’s passing-by-reference works, and mention that whilst your solution works in simple cases, it’s not behaviour you can depend on.

    0
    • 15

      Phillip Whisenhunt

      August 10, 2013 7:59 am

      Thanks for pointing that out Ingram, that is under the assumption that all of the properties are immutable. I’ve updated the article with a word of caution around using deep copies. Thanks!

      0
  5. 16

    Underscore.js doesn’t do deep copy, but optimised fork lo-dash does. Swap in lo-dash for underscore if you need deep copies and don’t need jquery.

    0
    • 17

      Phillip Whisenhunt

      August 10, 2013 7:44 am

      I completely forgot about Lo-Dashs capabilities of deep copying. I’ve updated the article to mention Lo-Dash as well. Thanks Luke!

      0
  6. 19

    This is nothing new to be honest, the web development world is just now catching up to object orientated world just now. These concepts have been around fir decades and most OO developers would use these techniques in web development anyway. I think it’s time web developers start reading up on OO.

    0
  7. 20

    Hi Phillip, thanks for this article. I was wondering in the example where you store the selected list item in the model if it would make sense to store it against the view since it would allow the model to remain faithful to the REST api server method?

    I can see that this is just an example though, and perhaps for another situation this may be more desirable.

    A similar question I’ve had whilst getting into backbone:

    What about things I may only want to exist on my client and not persist to the server. For example in a design app you may want to store tool palette states using the model view pattern for consistency with your other client side code but never persist the palette. In this instance should you bother with a model or just create a tool palette view and store the state as properties against the view?

    Any thoughts on this scenario appreciated.

    0
    • 21

      Phillip Whisenhunt

      August 11, 2013 2:18 pm

      No problem! I’m glad you liked it. Determining where to put extraneous view data is really a delicate balance between keeping your models faithful to REST and keeping your views as simplistic as possible. If the extra attributes you’re adding are centered around rendering, such as the height of a container, in my opinion they should be added to the view. If the attributes have anything to do with the underlying data model, then you may want to push that into the model. For example, if the list example were more flushed out and for some reason I only wanted users to be able to select a specific range of items from the list of items returned by the model, I would likely push that logic into the model. In short, as most things go, it really depends on your situation. You can argue for keeping your models truly faithful to REST and you can argue that you should keep your views as dumb as possible and push as much logic into your models.

      For the example that you’re describing I would definitely create a model. In doing so you have a clear separation of concerns and you get a lot of “nice to haves” from using a model, such as validation. I would also advise against storing view specific data in actual markup itself because it means that you have to query the DOM for state and you can end up adding extraneous classes that don’t have any presentational meaning. I hope this helps some! :)

      0
      • 22

        I see your point, that where you put extraneous data, be it view or model, mostly depends on what the data really is and what you need it for, but your example data strikes me as something that should be stored on the view, as it has to do with the user action of a visual selection, not data manipulation.

        I would consider expanding the example to include the full argument for storing on the view and for storing on the model, with examples of situations in which one or the other would make more sense. The example seems like it could lead some to over-bloat their models with view specific state data.

        Loved the article otherwise, great to see many things I do validated and great to learn a few new tricks :)

        0
        • 23

          Phillip Whisenhunt

          August 29, 2013 4:19 pm

          Thanks! I’ve updated the article with a bit more of a discussion around where to put extraneous data.

          0
  8. 24

    Good article!

    Since `validate` method in “BROADCAST CUSTOM ERROR EVENT” doesn’t return, Backbone treats the model is validated successfully.

    I think combining “RETURN AN ERROR OBJECT” and “BROADCAST CUSTOM ERROR EVENT” makes sense. Then we can use `invalid` and `invalid:ATTR` events in the same manner of `change` and `change:ATTR` events. This kinds of consistency is really useful, I think :)

    0
  9. 25

    Where would be a good place to start if I wanted to get into Jasmine but specifically combined with backbone, I have 0 experience with testing.

    Cheers

    0
    • 26

      Phillip Whisenhunt

      August 29, 2013 3:50 pm

      You may want to checkout Addy Osmani’s Backbone.js Fundamentals book as I believe it has an entire section dedicated to testing with Jasmine.js!

      0
  10. 27

    in Perform Deep Copies Of Objects sections, validate function is not called

    0
  11. 29

    in views you can use this.$('#a') instead of $(‘#a’, this.$el), much more elegant.

    0
  12. 30

    Great article! Covers a lot of ground. Also, thanks for the honorable mentions!

    0
  13. 32

    Looks like code in “Generic Error Display” section is broken or incomplete:
    1. set() function don’t use typeOfError param;
    2. set() function remove some classes but doesn’t add any class (I suppose it should use typeOfError param to define added class);
    3. this.model.on(‘error’) handler call alert.set() while it probably should be AlertView.set().

    0
  14. 34

    Hi, thanks for the pro tips. I am new to BackboneJs so I think I will be coming back to this article a few times.

    I created a jsfiddle of the Hotel example and noticed that you have a misplaced closing brace `}` before `})` – it should be after the defaults array.

    I think someone already mentioned that getRooms should return.

    Thanks again.

    0
  15. 35

    Just awesome! :)
    p.s: … and what about 6th Street? :)

    0
  16. 36

    Better if I create my own. This is too complex. I don’t like

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top