Backbone events are firing multiple times after re-rendering sub-views
backbone.js, javascript
Solution
I had exactly the same problem when I first started using backbone. Like Peter says, the problem is that you have more than one instance of the View being created and listening for the event. To solve this, I created this solution in my last backbone project:
/* Router view functions */
showContact:function () {
require([
'views/contact'
], $.proxy(function (ContactView) {
this.setCurrentView(ContactView).render();
}, this));
},
showBlog:function () {
require([
'views/blog'
], $.proxy(function (BlogView) {
this.setCurrentView(BlogView).render();
}, this));
},
/* Utility functions */
setCurrentView:function (view) {
if (view != this._currentView) {
if (this._currentView != null && this._currentView.remove != null) {
this._currentView.remove();
}
this._currentView = new view();
}
return this._currentView;
}
As you can see, it's always removing the last view and creating a new one, which then renders. I also add a require statement in the router because I don't want to have to load all views in the router until they are actually needed. Good luck.
Problem
We have a single Backbone view comprised of a sidebar and several sub-views. For simplicity, we've decided to have the sidebar and sub-views governed by a single `render` function. However, the `click .edit` event seems to be firing multiple times after clicking on one of the sidebar items. For example, if I start out on "general" and click `.edit`, then `hello` fires once. If I then click `.profile` on the sidebar and click `.edit` again, `hello` fires twice. Any ideas? View ``` events: { "click .general": "general", "click .profile": "profile", "click .edit": "hello", }, general: function() { app.router.navigate("/account/general", {trigger: true}); }, profile: function() { app.router.navigate("/account/profile", {trigger: true}); }, render: function(section) { $(this.el).html(getHTML("#account-template", {})); this.$("#sidebar").html(getHTML("#account-sidebar-template", {})); this.$("#sidebar div").removeClass("active"); switch (this.options.section) { case "profile": this.$("#sidebar .profile").addClass("active"); this.$("#content").html(getHTML("#account-profile-template")); break; default: this.$("#sidebar .general").addClass("active"); this.$("#content").html(getHTML("#account-general-template")); } }, hello: function() { console.log("Hello world."); }, ``` Router ``` account: function(section) { if (section) { var section = section.toLowerCase(); } app.view = new AccountView({model: app.user, section: section}); }, ``` Solution My solution was to change the router to this: ``` account: function(section) { if (section) { var section = section.toLowerCase(); } if (app.view) { app.view.undelegateEvents(); } app.view = new AccountView({model: app.user, section: section}); }, ``` This works for now, but will this create a memory leak?