Backbone bind event fired multiple times

10,298

Solution 1

Every time you click the red view or blue view -buttons you create a new Red or Blue View each and every time. You bind their events hash to respond to click DOM events originating from buttons with classes button and button2.

  1. Press 'red view' 3 times -> 3 instances of RedView created
  2. Click button with class 'button' -> DOM event
  3. 3 instances of RedView listening to said DOM event -> 3 alerts

This is because you don't clean the views before creating a new one effectively leaving you with ghost views that respond to events even though they can't be seen. (More info on the events hash) You can clean the events from you views with something like this.

cleanup: function() {
  this.undelegateEvents();
  $(this.el).clear();
}

Here is your fiddle with working cleanup of views http://jsfiddle.net/DwRRk/34/

Also a hint for good practice: you should use something like a render method to attach stuff to your DOM, use the initialize to just initialize the needed values for your view.

Solution 2

You are creating a new view everytime the buttons are clicked, without destroying the previous one. Try using a single view likes this:

http://jsfiddle.net/DwRRk/32/

var SomeModel = Backbone.Model.extend({});

var SomeView = Backbone.View.extend({
    el: "#container",
    model: SomeModel,
    events: {
        "click .button": "clickme"
    },
    clickme: function() {
        alert(this.model.get("color"));
    },
    colorChanged: function() {
        this.$el.html("<div id='" + this.model.get("color") + "_view'><div class='button'>Click Me</div></div>");
    },

    initialize: function() {
        _.bindAll( this, "colorChanged" );
        this.model.on("change:color", this.colorChanged );
        this.model.on("reset", this.colorChanged );
    }
});



$(document).ready(function() {
    //var router = new SystemRouter();
    var model = new SomeModel({color: "red"}),
        view = new SomeView({model: model})


    $('#but1').click(function() {
        model.set("color", "red");
    });
    $('#but2').click(function() {
        model.set("color", "blue");
    });
});​

Solution 3

Here's another way of deleting ghost views(what i'm using)

disposeView: function(view){
   Backbone.View.prototype.close = function () {
      this.unbind();
      this.undelegateEvents();
   };

   /* --Destroy current view */
   if(this.currentView !== undefined) {
      this.currentView.close();
   }

   /* --Create new view */
   this.currentView = view;
   this.currentView.delegateEvents();

   return this.currentView;
}

disposeView(new view());

Be sure to always return "this" in your view or else this won't work.

Share:
10,298
TonyTakeshi
Author by

TonyTakeshi

Updated on July 25, 2022

Comments

  • TonyTakeshi
    TonyTakeshi almost 2 years

    I am trying to build a switching view with backbone js and found out my bind event fired multiple times, when I switching view for few times.

    Below is the code for better illustration:

    html

    <div id='container'>
        halo world
    </div>
    
    <button id='but1'>red view</button>
    <button id='but2'>blue view</button>
    

    css

    #red_view{
        width:400px;
        height:400px;
        background-color:red;        
    }
    #blue_view{
        width:400px;
        height:400px;
        background-color:blue;        
    }
    .button,.button2{
        width:300px;
        height:300px;
        background-color:gray;
    }
    

    ​ javascript

    RedView = Backbone.View.extend({
        el: "#container",
        events:{"click .button":"clickme"},
        clickme:function(){
            alert('redview');                        
        },
        initialize: function(){
            this.$el.html("<div id='red_view'><div class='button'>Click Me</div></div>");            
        }
    });
    
    BlueView = Backbone.View.extend({
        el: "#container",
        events:{"click .button2":"clickme2"},
        clickme2:function(){
            alert('blueview');                        
        },    
        initialize: function(){
            this.$el.html("<div id='blue_view'><div class='button2'>Click Me</div></div>");            
        }
    });
    
    $(document).ready(function(){
        //var router = new SystemRouter();
    
        $('#but1').click(function(){
           var view = new RedView();
        });
        $('#but2').click(function(){
           var view = new BlueView();
        });    
    });
    

    If you click the red view for 3 times, and press 'click me'. It will pops up alert for 3 times as well. I suspect there's need to unbind the event somewhere, but couldn't find proper way to do it. Best to provide some references of doing this correctly.

    ​Here's the link to jsfiddle demo. http://jsfiddle.net/mochatony/DwRRk/31/