Lessons learned while working with Backbone.js

I was developing a quite big Backbone.js application with my team of 2 more members. We were working on this project for about 7 months. We’ve learned an awful number of things in this journey as it was our biggest Javascript project for everyone in our team. Among many other things, OOP in Javascript always confuses me though I understand a few things better than earlier. I’ve tried to write a few things I’ve learned while working in this project; however, everything does not directly related to backbone.js

Source Code is the best documentation

I have relied on the backbonejs.org for several months for documentation purpose. However, I’ve found not everything was documented properly in the website. For example, from the website I knew fetch/sync accepts success and error as property of the options hash. What I didn’t know until I read the source code is that it also triggers sync and error events on success and failure respectively. Reading the official doc, I thought it’s possible only for save() method.

Simplified Object Copying

If I need to copy a variable/object attribute, I first need to check it whether it exists or not. Look at this example:

if(this.someAttribute){
  var localAttribute = this.someAttribute;
} else {
  var localAttribute = this.someAttribute = {} //or any default value;
}

However, while reading Backbone.js source code, I’ve learned we could write this in a very simplified one line.

var localAttribute = this.someAttribute || (this.someAttribute = {});

Changing in referenced object does not trigger events

When you change an attribute of a backbone model, change and change:attribute  events are triggered. For example,

object.set(‘name’, ‘The HungryCoder’) will trigger change and change:name events on object.  The following will not work.

var info = model.get('userInfo'); //returns a hash
info['id'] = 101;
model.set('userInfo', info);

The above change won’t trigger a change event. Here info variable is a reference to model’s userInfo and userInfo attribute in the object is already updated when you set info[‘id’] = 101;

In such cases, if you want to trigger the change events, you need to clone the attribute at first place when you are copying them.

var info = _.clone(model.get('userInfo'));
info['id'] = 101;
model.set('userInfo', info);

This will trigger change and change:info events correctly.

Learn fighting Zombies

If you’re working with Backbone.js for a while, chances are high that you’re already facing this kind of problems. Sometimes, you will notice that a particular action is triggering more than once though it is supposed to perform only once.

This happens because, even though, you remove elements from your DOM, they are still alive in your computer’s memory. Consider the example:

 

var Views.MyView = Backbone.View.extend({
  initialize: function() {
    this.model.on('change', this.render, this);
  },
  render: function() {
    //render template
    alert('hello');
  }
});

You’ve taken instance of this view and added to your DOM. When you wanted to remove these elements from DOM, you’ve called remove() method on this instance. Though the elements are removed from DOM, they are still in memory and can’t be cleaned up by Javascript’s garbage collectors as this object is still referenced from your model. It is due to the following line that you’ve written in our earlier view.

this.model.on('change', this.render, this);

The model has still a reference to this view and a referenced object is not cleaned. So your view is still going to alert you even if they are not visible in the DOM. This has been addressed in Backbone.js 0.9.9 where listenTo (and stopListening) is introduced. So you re-write the above line as following:

this.listenTo(this.model, 'change', this.render);

This will internally keep track of the bounded events and will reliably unbind any events when you call remove() on this view object.

to be updated…