Reputation: 1799
Update: Per my comment, my problem was that I had an extra model that I was passing into the view that I was not unbinding events on. When I saw the event handler being triggered I assumed the source was from this.model instead of this.extra_model, because I had forgotten that this.extra_model was being used for error validations as well.
The solution was to add the following:
MyView = Backbone.extend({
//...
//add method to override BaseView
cleanUp: function() {
this.extra_model.off(null, null, this);
BaseView.prototype.cleanUp.apply(this, arguments);
},
//...
});
Thanks for reviewing the problem, and sorry for the programmer error.
All: I'm having a problem with stale/zombie events still being bound after I've cleaned up a view. The problem comes when I bind a custom event to a model. When I remove the view from the dom, I call 'this.model.off(null, null, this);' as suggested on various message boards, but although I can see the 'custom-handler' callback getting deleted in chrome debugger tools, I still notice the event handler for 'custom-handler' getting called more times than it should (one extra for every time I recreate the view after cleaning it up) when triggering the event. Could someone tell me if my clean up code is missing something? Thanks in advance!
BaseView = Backbone.extend({
//...
displayErrors:function(){},
cleanUp: function(){
if (this.model) this.model.off(null, null, this);
if (this.collection) this.collection.off(null, null, this);
if (!this.options.persistDataAfterViewCleanup) {
if (this.model) delete this.model;
if (this.collection) delete this.collection;
}
//_.each(this.subViews, function(view){view.cleanUp();}); not needed yet.
this.undelegateEvents();
$(this.el).removeData().unbind();
//Remove view from DOM
this.$el.html('');
this.remove();
}
});
MyView = BaseView.extend({
initialize: function(){
//called manually from model using trigger
this.model.on('custom-handler', this.displayErrors, this);
}
});
Upvotes: 4
Views: 1699
Reputation: 35890
Assuming you are on the newest version of Backbone (0.9.10
), you should use the new Backbone.Events.listenTo
method to bind your events listeners. Using this method Backbone will keep a reference to the object, and clear all event bindings automatically upon view.remove()
:
this.listenTo(this.model, 'custom-handler', this.displayErrors);
All the things you do in your cleanUp
method (delete
, undelegateEvents
, removeData
, unbind
, $el.html('')
) look a lot like voodoo programming. None of those steps should be necessary at all.
Your zombie views are most likely due to some reference to the view being held by your own code, either directly or indirectly. A reference can be held by an event handler, a bound function, an exported closure, or any number of things. I suggest you try to analyze your code, and use Chrome Developer Tools' Heap profiler tool to try to find the retained objects and their referencers.
Check out my answer in this SO question, where I describe a simple method for finding memory leaks in specific code paths. While your problem is not directly about leaking memory, it's about leaking references, whose retained heap size should help you find what's holding onto them.
Upvotes: 5