Search code examples
javascriptjquerybackbone.js

listenOnce() running twice in backbone.js event


I had asked a question here that referred me to use using the backbone events. It works great, except that my event listener onFormSubmit() gets called twice. Normally I wouldn't care, but I have a function that toggles some states, and toggling this twice creates a problem.. I thought my view was being rendered twice (based on other answers on SO), but it does not appear to be so. I am trying to understand the 'why' behind what is happening here.. Here is some code (with non-relevant stuff removed)..

Here is my article form view that calls triggers the events on a form save and it gets triggered once (correct intended behavior) and it gets redirected back to the dashboard..

var PostView = Backbone.View.extend({
  el: '#content',

  articletemplate: _.template($('#article-template-add').html()),

  initialize: function() {
    this.render();
  },

  render: function() {
    this.$el.html(this.articletemplate({}));
  },

  events: {
    "click .save": "savePost",
  },

  savePost: function() {
    var mypost = new PostModel();
    this.model = mypost;
    this.model.save(null, {
      success: function(model) {
        eventBus.trigger('formSubmitted', {
          message: "form submitted"
        });
        app.navigate("/", false);
      },
    });
  },
});

Here is my Dashboard view() that gets called after the form submit above.. Here is where onFormSubmit() executes twice (the console.log() gets printed twice).

var DashboardView = Backbone.View.extend({
  el: '#content',
  dashboardtemplate: _.template($('#dashboard-template').html()),

  initialize: function() {
    this.listenToOnce(eventBus, 'formSubmitted', this.onFormSubmit);
    this.render();
  },

  onFormSubmit: function(datahere) {
    console.log("onFormSubmit called"); // *** This gets printed twice
  },

  render: function() {
    $(this.el).empty().html(this.dashboardtemplate(this.model.attributes));
  },
});

Now, I am beginning to think that there might be some problem in the main app routing?

var AppRouter = Backbone.Router.extend({
  routes: {
    "": "dashboard",
    "article/add": "addarticle",
  },

  dashboard: function() {
    mydashview = new DashboardView();   
  },

  addarticle: function() {
    var articleView = new PostView();
  },
});

var eventBus = _.extend({}, Backbone.Events);
var app = new AppRouter();
Backbone.history.start();

EDIT

I updated the savePost() to include that the trigger is called in the callback of the this.model.save()..I've forced it to create a dummy model instead of taking it from a form. The good news is that I was able to recreate the behavior here: http://jsfiddle.net/okswxngv/ If you open your console, you can see the onFormSubmit called printing twice.


Solution

  • Your problem is linked to the ghost view. Some call it zombie. The DashboardView is created every time you enter the root page, but never removed.

    That is why he is going to exist, even if you link a new view to the #content div.

    You can put a break point on DashboardView ->initialize and see that is called twice.

    To better understand I have changed you code and added a name to the view (which is the date when it was created) and printed this name.

    To get read of the problem you have to remove the unneeded view when you create a new one.