« Back to home

Properly disposing a View in Backbone JS

I've been working with Backbone.JS since the 0.9.10 release and one thing that I found cumbersome is on how to dispose a "View" properly.
I love Backbone.JS due to its flexibility but with that comes some drawbacks. Backbone.JS provides the basic framework to build upon your app
(validation, data modeling, events delegation, etc.) but moving from a basic to a more advanced architecture requires a lot more leg work. You also have to understand how Backbone operate deeply and knowing how to debug properly not just from Backbone's perspective but all the components
that are tied to your application.

So how do you properly dispose a View? Disposing a View doesn't necessarily mean that need to get rid of the actual View "element" but rather clean up
the attached events (after switching to another view, etc.) and make sure that when you create a new instance of the same View, you're not going to
have multiple events delegated to the same element. This issue is commonly referred to as Zombie Views where events hangs out after the fact and
transitioning to a different View instance. Since the apps that are mostly built around Backbone are "single page application", this is a common issue.

If you're a normal developer and you happen to read through the Backbone documentation, removing a View should look like this and is very simple:

view.remove();  

As far as 'Events' goes, Backbone usually 'undelegate' those Events automatically for you if you add Events like this in your View.

events: {  
    'click .button' : 'doSomething'
},
doSomething: function(ev) {  
    ...
}

It becomes a little more complicated when you're triggering 'Events' outside the premises of the Events that has been declared in the View.
One example is when you use a 'Modal' plug-in where a function isn't declared where they normally are. Another example is when you have 'Sub Views'
(children) within one View.

A quick check for getting the Events attached to your "el" (the actual view) is to loop through it like this. This is a good way to check on
whether Events are showing after doing a view.remove(). If it doesn't then you got some issues!

var elEvents = this.$el.data('events');  
if (data_events) {  
   $.each(this.$el.data('events'), function (i, e) { 
     console.log(i + ' - ' + e); 
   });
}

Searching the web will tell you do something like this to not just remove the View but to also unbind any events tied to it:

view.remove();  
view.unbind();  

Since the framework and JavaScript libraries changes drastically by the day, it can be hard to keep up with what's the latest and greatest approach to doing something.
As of jQuery 1.7 release, the preferred way of undelegating events is to use (who knows what's the next preferred approach):

this.$el.off();  

To put it all together, you can create a "Base" View that the child views can inherit from and you can simply just call this method when you want to Dispose a View.
Or you can just create a close function in your view if you want to keep things simple.

/** The base View that will contain logic that 
          will be consumed by other Views.*/
var BaseView = Backbone.View.extend({  
    dispose: function() {
       this.remove();
       this.off();
   }
});

/** A View implementation */
var ViewA = BaseView.extend({  
    close: function() {
        /** Call to dispose View */
        this.dispose();
    }
});

Hope that helps some people.

Comments

comments powered by Disqus