简体   繁体   中英

Backbone events are firing multiple times after re-rendering sub-views

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?

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.

Sounds like you are attaching multiple view instances to the same DOM element and they are all responding to the events. Are you making a new view each time you navigate without removing the previous view?

I have a dynamic view, that renders different templates inside the same element (about 12), based on router params. Now, the container in which the view renders, is defined inside the view.render() like so "el: '#some-container'". Naturally, i have to remove the view if it exists, before creating a new or the same one, to prevent zombies and s#!t. Just as a reminder, calling view.remove(), actually removes '#some-container' from the DOM, meaning the view has no place to render in, except for the first time. Now, there are dozens of methods to prevent this from happening. Just thought i should share in case anyone needs to save a few hours of research.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM