Zombies! RUN! (Managing Page Transitions In Backbone Apps)

One of the common issues or questions I see for Backbone.js goes something like this:

“Whenever I hit the same route more than once, I end up getting seeing this call being made multiple times. It seems to accumulate another call every time I hit the route. What’s going on?”

or

“I’ve noticed that my views are still handling events after I remove them from the screen. How do I stop this from happening?”

or

“How do I make sure I clean things up when moving to a new page in my app?”

At the heart of all of these questions is a problem that most backbone developers will run into at some point: zombies. That’s right – the living dead creatures and plague us and cause problems… only in this case, we’re referring to zombie objects in an application – otherwise known as memory leaks.

The Plague: Event Binding

The majority of the problems that people are referring to in these questions and issues are caused by the events that we bind to in our apps. Given that Backbone is an event-driven framework, it stands to reason that we’re going to be using a lot of events; and events are everywhere in Backbone apps.

We bind events to our DOM elements using the declarative `events` configuration in our views:

MyView = Backbone.View.extend({

  events: {
    "click #someButton": "doThat",
    "change #someInput": "changeIt"
  },

  doThat: function(){ ... },
  changeIt: function(){ ... }
});

We bind events from our models and collections so that our views can respond to changes and re-render themselves:

MyView = Backbone.View.extend({

  initialize: function(){
    this.model.bind("change", this.render, this);
  },

  render: function(){ ... }
});

We even use Backbone.Events in our own objects so that we can create application-level events and event-driven architectures for our apps.

MyView = Backbone.View.extend({

  initialize: function(){
    this.options.vent.bind("app:event", this.render, this);
  },

  render: function() { ... }
});

var vent = new _.extend({}, Backbone.Events);
new MyView({vent: vent});
vent.trigger("app:event");

Events are everywhere, and with good reason. They allow us to write modular, reactive code. We don’t have to stick to procedural loops and long methods that check state in order to figure out what to do next. Events allow us to know when state has changed and respond to that change appropriately.

Problems arise, though, when we bind objects together through these events but we don’t bother unbinding them. As long as these objects are bound together, and there is a reference in our app code to at least one of them, they won’t be cleaned up or garbage collected. The resulting memory leaks are like the zombies of the movies – hiding in dark corners, waiting to jump out and eat us for lunch.

For example – Backbone apps tend to have one or more areas of the screen that are updated with different views based on what the user is doing. It’s common to see a main area where the focused content is displayed, as well. When we the user interacts with our app, we update this area of the screen by having a new view instance render some new content for us. The result is new information being displayed for the user, as we expect.

The problem, though, is that it’s easy to write our code in a manner that doesn’t let us properly clean up our views when switching them out. For example, we could have a router with route methods that instantiate new views and simply replace the html of our main content area:

MyRouter = Backbone.Router.extend({
  routes: {
    "": "home",
    "post/:id": "showPost"
  },

  home: function(){
    var homeView = new HomeView();
    $("#mainContent").html(homeView.render().el);
  },

  showPost: function(id){
    var post = posts.get(id);
    var postView = new PostView({model: post});
    $("#mainContent").html(postView.render().el);
  }
});

This has the desired effect, visually. A user hitting either of these routes will see the content they expect to see. Unfortunately, though, any events that we’ve bound in our view may still be hanging around.

Rule #2: Double Tap

To correct this, I like to introduce an application object that manages the transitions between my views. This object is solely responsible for managing the content of a specific DOM element, displaying what needs to be displayed and cleaning up anything that no longer needs to be there.

function AppView(){

   this.showView(view) {
    if (this.currentView){
      this.currentView.close();
    }

    this.currentView = view;
    this.currentView.render();

    $("#mainContent").html(this.currentView.el);
  }

}

With this in place, we can re-write our router to have a reference to an AppView object. Then, when a route method is fired, the router will tell the AppView instance to display the new view for us. Since the AppView knows about the previously displayed view still, it can call any clean up code that we need for that view.

MyRouter = Backbone.Router.extend({
  routes: {
    "": "home",
    "post/:id": "showPost"
  },

  initialize: function(options){
    this.appView = options.appView;
  },

  home: function(){
    var homeView = new HomeView();
    this.appView.showView(homeView);
  },

  showPost: function(id){
    var post = posts.get(id);
    var postView = new PostView({model: post});
    this.appView.showView(postView);
  }
});

Now our router doesn’t have to worry about creating zombies. We’ve effectively managed our application’s view transitions by introducing an object who’s sole purpose is that transition management.

Closing A View

In this AppView example, I’ve chosen to have the it call a `.close()` method on every view that it is removing from the screen. There isn’t a method called ‘close’ on a Backbone.View, by default. We need to add this method ourselves, as a convention for our application to follow.

We can add our close method to our views a few different ways: add the method to every view in our app, create our own base view with this method, or add it directly to the `Backbone.View.prototype`. There’s not necessarily anything wrong any of these choices, though my preference is to build a basic close method into the Backbone.View.prototype.

There’s a common bit of functionality that each of our views will need when closing, in most cases. We need to unbind the DOM element events, we need to unbind any custom events that our view raises, and we need to remove the HTML that represents this view from the DOM. These three things can be done in two lines of code inside of our `close` method:

Backbone.View.prototype.close = function(){
  this.remove();
  this.unbind();
}

The call to `this.remove()` delegates to jQuery behind the scenes, by calling `$(this.el).remove()`. The effect of this is 2-fold. We get the HTML that is currently populated inside of `this.el` removed from the DOM (and therefore, removed from the visual portion of the application), and we also get all of the DOM element events cleaned up for us. This means that all of the events we have in the `events: { … }` declaration of our view are cleaned up automatically!

Secondly, the call to `this.unbind()` will unbind any events that our view triggers directly – that is, anytime we may have called `this.trigger(…)` from within our view, in order to have our view raise an event.

The last thing we need to do, then, is unbind any model and collection events that our view is bound to. To do this, though, we can’t use a generic close method on our base view. If we tried to, we would likely end up writing a lot of extraneous code and potentially slowing our app down or causing issues by accidentally unbinding all events for the model or collection, everywhere. If we have multiple views listening to events on the same object, this would remove the ability for our app to respond to the model and collection changes correctly.

The solution, then, is to take a page from the WinForms / .NET world and have an “onClose” method that any view can implement when it needs to have custom code run, when the view is closed:

Backbone.View.prototype.close = function(){
  this.remove();
  this.unbind();
  if (this.onClose){
    this.onClose();
  }
}

Then in a view that has bound itself to a model or collection event, we can provide an implementation of onClose:

MyView = Backbone.View.extend({
  initialize: function(){
    this.model.bind("change", this.render, this);
  },
  render: function(){ ... },

  onClose: function(){
    this.model.unbind("change", this.render);
  }

});

Our view will now be correctly cleaned up when the AppView calls the close method.

More Than Just Views For Zombies

Of course there are far more potential zombies in our Backbone apps than just views. Any time we make a call to the `.bind(…)` method on any object, we need to be aware of the lifespan of the objects involved. If the objects are going to live for the span of the application’s life, then we may not need to do any clean up. If the objects are temporal, though, it’s likely that we will need some sort of cleanup in place.

We all need to be good citizens of the potential zombieland in stateful, event-driven application development. Know the rules, stay safe, and above all don’t be a hero.

 

P.S.

I’ve learned a lot about JavaScript and Backbone memory management since I wrote this. If you want to keep up to date and get the latest info, join my mailing list. I’ve got a lot of insight to share and you don’t want to miss out!


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Backbone, Javascript, Model-View-Controller. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Daniel

    Just wanted to say a big Thank You for this excellent article. I’ve had this problem and “solved” it by calling jQuery’s undelegate and unbind before rendering my views, but this solution is far superior, will definately be using this. Once again, thanks, and keep up the good work!

  • http://twitter.com/shaunoconnor Shaun O’Connor

    Great article… coming from  OOP languages and building view heavy applications this is exactly what you need when using Backbone.js. 

    • http://mutedsolutions.com Derick Bailey

      thanks! :)

      and i agree – the OO aspect of building good backbone apps is what really made me fall in love with it, having spent many years building MV* winforms app.

  • Jay Turpin

    Derek – thanks for the post. Very well written and
    informative. I have a couple questions:

    ·         
    From a design perspective, you chose to add
    close() and onClose() directly to the View prototype, but you didn’t add
    showView(view) to the Router prototype. Any specific reason for these two
    different approaches? Have you run into need to send in different types of
    AppView objects?

    ·        
    Do you need to cleanup a binding that looks like
    this? Or are the bindings on the view automatically cleaned up when the view is
    closed?:

    view =
    Backbone.View.extend({

        tagname: ‘li’,

        initialize: function
    () {

            _.bindAll(this,
    “render”);

        },

        render: function
    () {

           // render logic

    return this;

        }

     
    });

     

    Thanks again for all the great information

    • http://mutedsolutions.com Derick Bailey

      hi Jay,

      for the showView method: it’s not a routing concern. routing is an entry point into the application that uses a tokenized representation of the application state (the route itself) to determine what the app should look like and act like when the route method fires. you may or may not have to show a view when a route method fires. i’ve built a few applications that don’t – the route methods call models to set specific state and then views are rendered based on the model state changes.

      you could put the showView method directly into the router if your app is small and you don’t need to worry about mixing those concerns too much. but i wouldn’t put it on the router’s prototype since it won’t be needed on _every_ instance of a router that you have. 

      (fwiw: having built a handful of apps with a router, controller and appview separated out, it’s become my default implementation because i know how to scale it out as the app grows)

      for the _.bindAll bindings: this binding lives and dies with the view instance so there’s no need to worry about it. even if you decided to pass a different object as the first parameter – for example: _.bindAll(someModel, “someMethod”, “anotherMethod”) – the binding would still die with the view instance because it’s the view that references the model. 

      hope that helps!

      • Jay Turpin

        Thanks! That helps clear a couple things up for me

  • http://twitter.com/ojohnnyo Johnny Oshika

    Thanks Derick for the great information you’ve been sharing about Backbone.  I’ve been using a slightly different technique for cleaning up the model/collection event bindings that my views have subscribed to and it’s been working well for me so I thought I’d share.  I’ve also shared this with the folks who are writing the Backbone JS on Rails ebook and I believe it’s made its way into the book:

    Inside a base View (or in your case the View prototype), I keep track of all the events that the view has bound to.  I also have a method that unbinds everything automatically:

    bindTo: function (model, ev, callback) {
    model.bind(ev, callback, this);
    this.bindings.push({ model: model, ev: ev, callback: callback });
    },

    unbindFromAll: function () {
    _.each(this.bindings, function (binding) {
    binding.model.unbind(binding.ev, binding.callback);
    });
    this.bindings = [];
    },

    In your cleanup “close” method, I would add this:

    this.unbindFromAll();

    Whenever a view needs to bind to an event, I do something like this:

    this.bindTo(this.model, ‘change’, this.someCallback);

    The benefit of this technique is that all of the events that my view has bound to get unbound automatically whenever the view is “closed”.  This way, I wouldn’t have to have an onClose method on all of my views to undo the bindings.

    Keep up the great work!

    • http://mutedsolutions.com Derick Bailey

      that’s brilliant! i’m going to have to try this out on my next project :)

  • http://twitter.com/bemusedjohnny Johnny Green

    Hey Derick, really appreciate this post.  I took this and went a step further with non-destructive view management baked in.  Multiple container management.  Let me know if i’m doing this wrong!

    https://gist.github.com/a5e924419628e54d91cc/697d6dfe165d7b3926f84a5dde7d50aa48a54a3a

  • http://twitter.com/davehoff Dave Hoff

    Just have to tell you how much I appreciate your awesome posts regarding Backbone best practices. Brilliant stuff!

  • Patrick

     Great post! I didn’t realize your events are still bound after the .remove() call, glad to know this.  Time for some code cleanup tonight :)

  • http://twitter.com/ataraxia_status Nick Pannuto

    Your `backticks` aren’t working

    • http://mutedsolutions.com Derick Bailey

      yeah – i know… i keep hoping i’ll find a WordPress plugin that translates backticks into inline code blocks, like Github wiki does. one of these days, and then magically all my posts will be extra awesome! :P

      • http://twitter.com/ataraxia_status Nick Pannuto

        Dude why would you use a wordpress plugin for that? You could do that with a tiny piece of javascript. 

  • Andy

    Great article.

    How would you handle removing multiple views in the following common pattern, is this handled by backbone when the collection is reset or would you need to save all the old views in an array and loop over closing each of them?
    // current
    var listView = Backbone.View.extend({
      initialize: function(){
        this.collection.bind(‘reset’, this.addAll)
      },
      addAll: function(){
        $(this.el).empty();

        this.collection.each(this.addOne);

      },
      addOne: function(item){
        var view = new itemView({model:channel, app:this.options.app})

        $(this.el).append(view.render().el);
      }});

    // alternate
    var listView = Backbone.View.extend({
     views : [],
      addAll: function(){
        this.closeAll()
      },
      addOne: function(item){
        this.views.push(view);
      },
      closeAll: function(){
        $.each(this.views, function(view){
          view.close();
        })
      }
    })

    • http://mutedsolutions.com Derick Bailey

      hold them in an array and loop through them is the easiest way i’ve seen for handling that. i built that in to my Marionette plugin, for example. any time you have a CollectionView instance, it stores the child views in an array. closing the CollectionView will close all of the children

  • Varand

    I have a question,:

    where should I put Backbone.View.prototype.close = function(){/*code*/}
    ???? inside that zombie view?or in Backbone.js under // Backbone.View
    or inside _.extend(Backbone.View.prototype, Backbone.Events, {…}
     

  • Randy Kleinman

    5-appview.jsIs the code in “5-appview.js correct? I am getting syntax errors in firebug complaining about the syntax on this line:

    this.showView(view) {

    • http://mutedsolutions.com Derick Bailey

      … it does look a little off now that you mention it. check out the updated version of this, called RegionManager: http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/ it’s the same concept, just solidified a little more.

      • Stark

        You should mention this in an update on this post – I was having same issues with this, but the updated code is way more solid!

  • http://twitter.com/wireddaniel Daniel Murphy

    Thank you!

  • https://paydirtapp.com/ Tristan

    You saved the day, Derick. Can’t thank you enough.

  • Orangewarp

    It’s funny. Every time I run into a problem, I do a Google search and somehow, quickly find myself back here… Your articles are very clearly written, informative, and have been uber-helpful. Thanks!

  • Marco

    Thanks for a nice article! I wonder if there’s a way to double check if the old views and bindings (including sub views) are removed for sure? I was thinking about something like check if a closed view with a specific cid still exists in memory. But from what I have read, you can’t fetch a view by it’s cid? Maybe there’s a way to check which views exists in memory at a specific point?

    • http://mutedsolutions.com Derick Bailey

      There’s no way to do that at run time. You could keep a list of open views around, but that list would keep all of your views around simply by having a reference to them. They would never close. Backbone doesn’t keep a list of open views around, specifically for this reason. You can run a memory profiler in your browser (built in to chrome, safari, firebug, etc) but that’s a development tool and not something you can do in production with other people’s browsers. Your best bet is to use the development tools and memory profilers during your own testing, to make sure you’re cleaning things up… and then trust that it’s all good when it goes to production.

  • http://scottyapp.com Martin Wawrusch

    This is so politically incorrect. They are called ‘Undead Americans’ these days ;P 

    Great article, thanks for writing it.

  • Anonymous

    Hmm does this (http://documentcloud.github.com/backbone/#Events-off) change how you’d approach this topic? Backbone 0.9.x introduced some new event handling business.

  • Chris Barry

    Hi Derick,

    Thanks for this, and your other article too, really helpful. I think I may just being a bit stupid and not reading your articles properly or checking out your marionetee plugin, but would you have any views on this question?

    http://stackoverflow.com/questions/10259346/backbone-js-large-mutli-page-app-manage-page-transitions-cleanly-destruction-c 

  • Amit Garg

    Everytime I search for Backbone .. I land on your page.. then the search ends..  Thank you very much .. Keep posting..

  • http://twitter.com/vlycser Cristhian Valencia

     Excelente articulo muchas gracias.
    Yo intente realizarlo de una forma alternativa y obtuve lo siguiente:

    http://stackoverflow.com/a/10559519/1359480

  • Ansjob

    Really neat solution to this problem. Love it!

  • UBT

    Thanks for the article Derick. One naive question though, won’t removing the view take it out of DOM and what will be pattern to add it back again.

    • http://mutedsolutions.com Derick Bailey

      Yes, that’s the point.

      If you need to add it back again: http://tbranyen.com/post/missing-jquery-events-while-rendering

      But I don’t recommend doing this. I recommend creating a new view instance instead. Re-using views always leads to more trouble than its worth.

  • Sebastien Hiticas

    Saved my day! Tks!

  • Bill

    thanks, Derick. I really like this AppView pattern. I’m fairly new to backbone, but I’m usually wrestling with when to render a view. I think as a rule of thumb I’ll stick to is:

    1. call render explicitly on the view if it is affected extenally –such as swapping out main content for a single page app

    2. render (all or portions) of the view based on model changes if there is some “internal” state change in the underlying model(s) –such as a field value update or such
    I come from a knockoutjs background so am used to always rendering based on model changes and never rendering explicitly so the transition is a little wierd for me :)

    Anyway would love to hear your thoughts on my “rule of thumb”

  • Alex

    Great article Derrick. This is just what I have been looking for. I am wondering if this is necessary for apps that don’t have a lot of views? And also, will this take care of nested views?

    • http://mutedsolutions.com Derick Bailey

      it doesn’t matter how many views the app has. if you are removing a view instance and putting another one in it’s place, you need to manage your view’s closing and cleanup.

      as for nested views – not directly. you need to add additional code to your “close” method to close each of your nested views.

      FWIW: the views in my Backbone.Marionette plugin handles nested views

  • v1rn3ss

    Hi, why not using $(“body”).unbind(); in the view constructor Iinitialize() .. It will unbind all events and view events will be rebounded in the view events object. I have the same architecture as you and it works great. Correct me if im wrong.

    • http://mutedsolutions.com Derick Bailey

      that will unbind all DOM events for all DOM elements on the screen. If you have more than 1 view on the screen, and you are only trying to unbind one of them, unbinding all of them would be a very bad idea. I typically have 10, 15, or as many as 40 or 50 views on the screen at once. … very bad idea. don’t do that.

  • Nikhilesh

    Thanks a lot for this article Derick. I encountered the exact same issue mentioned in this post, where my event handlers were getting called multiple times. I could only solve it after reading this article.

  • Fabrice

    Thank you for this post. I think it’s kinda weird that the backbone.js doc doesn’t warn developers about these issues

  • Anonymous

    Nice article, thank you for making us aware of that problem :)

  • Anonymous

    Hi Derick, I wonder if `onClose: function () { this.model.unbind(“change”, this.render) }` is necessary. Won’t `this.model` be garbage collected automatically with the view? Thanks.

    • http://mutedsolutions.com Derick Bailey

      it is necessary for scenarios where the model is use in places other than this one view. if both the model and view are created and destroyed together, then they will both be garbage collected. but if the model is used elsewhere, even for one line of code outside of the view (like creating the model to pass in to the view – which is what you should be doing) you run in to the potential for a memory leak, even if it’s only for a short period of time.

  • Perry Tew

    Derick,
    I’ve really enjoyed your backbone posts as well as your contributions to stackoverflow. You’ve been instrumental in helping me learn backbone. Thank you.

    • preeti

      i am using jquery delgates in each view.js.if i use
      $(this.el).live(‘pagehide’, function (event, ui) {

      $(this.el).remove();
      });

      will that work equivalent to remove zombies and
      2nd Doubt my application is working slow so i m not getting clue how to increase the frame rate.Could you suggest Something…thanks in Advance

  • Michiel van Eerd

    Great article! But isn’t it also possible to change the close method like this:

    Backbone.View.prototype.close = function() {
    this.remove();
    this.unbind(); // alias of this.off();
    if (this.model) {
    this.model.off(null, null, this);
    }
    if (this.collection) {
    this.collection.off(null, null, this);
    }
    }

    This way all event handlers that are bound to the model or collection by this view are automatically being removed.

    • http://mutedsolutions.com Derick Bailey

      Possible, yes. But it’s a bad idea in many cases and not worth the possible problems that this would cause.

      If you have multiple views in your application that are binding to the same model or collection, closing this view would unbind all model events for all views that are attached to this model or collection. Your entire application would stop responding to the model changes, not just this one view.

      • Michiel van Eerd

        Hi Derick, thank you. Maybe I’m wrong, but the code above only removes the callbacks for the model of *one specific view*, not all. If you look at the backbone documentation:

        // Removes all callbacks for `context` for all events.
        object.off(null, null, context);

        // Removes all callbacks on `object`.
        object.off();

        So when a view calls this.model.off(null, null, this), where “this” references
        the view, only the callbacks for the model of this view are removed,
        and no other views are affected.

        • http://mutedsolutions.com Derick Bailey

          ah, sorry. somehow missed that you were passing in the context variable. that might work. i don’t know for sure, but you could test it out and see pretty easily :)

          • http://twitter.com/tommoor Tom Moor

            This approach seems to work really well, I’ve combined it with also having an optional onClose event so that individual views can tidy up anything specific such as events bound directly to the window.

  • Salman

    Thank you Derick. We are also working with backbone on a large scale app and the first thing we hit upon was this very issue.
    This was a great help and nice read.

  • Miguel

    Is there a reason why you chose to create a ‘close’ method rather than overriding the ‘remove’ method?

    • http://mutedsolutions.com Derick Bailey

      semantics, and purpose.

      the remove method is a convenience method that wraps “this.$el.remove()” and is used to remove the view’s “el” from the DOM. this has a very different set of semantics than “close” does.

  • dcz.switcher

    Thanks to share your knowlesges, just a question, imagine a list view of something and a detail view
    can I just define a new model for detail view and render it ?

  • http://twitter.com/c_behrens Christian Behrens

    Very comprehensive and informative post. Keep up the great work!

  • Weft

    Great article!. thanks you for help me to kill the zombies

  • preeti

    Derick,

    i am using jquery delgates in each view.js.if i use
    $(this.el).live(‘pagehide’, function (event, ui) {
    $(this.el).remove();
    });

    will that work equivalent to remove zombies and
    2nd Doubt my application is working slow so i m not getting clue how to increase the frame rate.Could you suggest Something…thanks in Advance

  • Flor

    Any idea if this will work with Backbone.CollectionBinder and Backbone.ModelBinder? I tried technique in this post after my collection seems to be ‘lost’ after hitting the browser back button but looks like it didn’t fix this (Unless I did something wrong, completely possible)

  • http://twitter.com/johannesmauerer Johannes Mauerer

    Little late to the party but thanks for the good posts. Have been more than once at your blog now since starting nodeJS :). Thanks!

  • Matt

    Doesn’t this.remove() remove the element associated with the view rather than just “the HTML that is currently populated inside of `this.el`”.

    • http://mutedsolutions.com Derick Bailey

      yes it does. i said that wrong in the article

  • http://twitter.com/m_i_c_h_a_e_l_m Michael Mitchell

    You are awesome. Thank you for this.

  • Thalis Kalfigkopoulos

    I may be mistaken, but shouldn’t line 3 of the Appview definition be:

    this.showView = function(view) {…}

    Instead of the shown:

    this.showView(view) {…}

  • jami

    Thanks for such a comprehensive post.

    I had what I thought were zombies, but no, it was just that I was instantiating a view twice with the same event, and I only wanted it to fire for one of the instances. I solved it by taking the events out on instantiation and using Backbone’s delegateEvents() function when I needed the event to be bound.

  • http://www.facebook.com/neil.young1 Neil Young

    Thanks for the great code although I am finding using this kills the events in my views when using your app view as the events are setup on the element in the object and then added to the #mainContent div ?

  • m4cm3nz

    Great!! I really don’t like the blog’s logo and layout, but the content is awesome

  • http://twitter.com/mrjoelkemp Joel Kemp

    Bless your soul.

  • Vignesh Nandha Kumar

    Hi, isn’t the problem we are trying to solve by adding the `onClose` callback already solved by `stopListening`, which is called automatically by Backbone during `view.remove`?

  • Sam

    Please use new Backbone.Events.listenTo instead of Backbone.Events.on

  • http://www.facebook.com/vikram.pawar1 Vikram Pawar

    Thanks dude. You’re a life saver!

  • Dave Stewart

    Not sure if this article is still taking comments, but why destroy and create views the entire time? Surely it makes more sense to create the views once, bind the events, cache them in a views object/ array, then re-render and show/hide them as the application requires? (Obviously there’s no point re-rendering hidden views, so you;d flag this). I’m just starting Backbone now, but was an AS3 dev for years and we used to do this kind of thing daily.

  • dmackerman

    Good article, thanks!

    You are creating a new close() function, but does the new View.remove() function in Backbone 1.0 do the same thing essentially? I quote:

    “Removes a view from the DOM, and calls stopListening to remove any bound events that the view has listenTo’d.”

  • M.

    Derick, thank you for your posts, very usefull reading.

  • Danish Aziz Satkut

    Great article and nice references to Zombieland.

  • http://rommelxcastro.com/ Rommel Castro A.

    i really like this approach! really useful, thanks

  • miopatre

    It’s been 2 years since the last update so I believe now, BB version 1.0.0, it is worth mentioning that Backbone.View::remove eliminates “zombies” in a sufficient way

  • http://blog.untrod.com/ Chris Clark

    Derick – this is just great. We hadn’t been careful managing our views and as our app grew it became more and more “stateful” as bits of views left pieces of themselves behind. I spent the afternoon ripping through our router and implementing this pattern, and our code is suddenly more readable and structured, our routing code is considerably shorter, and I have a feeling it’s going to eliminate a whole category of bugs

  • sSaroj

    Thanks a lot Derick. The zombie views were killing me literally ;).

    A blog also can kill the zombies..

  • ian0

    Humble bow. Thanks Derick.

  • http://www.prideparrot.com/ Vijaya Anand

    Hey very helpful info. Thanks man.

  • http://lee101.github.io lee101

    Awesome article.

    Looks like you have a syntax error in rule #2

    function AppView() { ..

    `this.showView(view) {` —should be—->> `this.showView = function (view) {`