Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone bind event fired multiple times

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/

like image 313
TonyTakeshi Avatar asked Jun 26 '12 07:06

TonyTakeshi


2 Answers

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.

like image 111
jakee Avatar answered Sep 25 '22 17:09

jakee


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");
    });
});​
like image 30
Esailija Avatar answered Sep 25 '22 17:09

Esailija