最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Backbone bind event fired multiple times - Stack Overflow

programmeradmin1浏览0评论

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. /

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/

Share Improve this question asked Jun 26, 2012 at 7:37 TonyTakeshiTonyTakeshi 5,92910 gold badges54 silver badges72 bronze badges 1
  • 1 You are not cleaning your views up, leaving you with ghost views. Check my answer below! – jakee Commented Jun 26, 2012 at 8:01
Add a comment  | 

3 Answers 3

Reset to default 13

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.

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");
    });
});​

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.

发布评论

评论列表(0)

  1. 暂无评论