Backbone.js View can't unbind events properly

前端 未结 5 1920
执笔经年
执笔经年 2020-12-25 08:11

I have some Backbone.js code that bind a click event to a button, and I want to unbind it after clicked, the code sample as below:

var AppView = Backbone.Vie         


        
相关标签:
5条回答
  • 2020-12-25 09:06

    You could solve this another way

    var AppView = Backbone.View.extend({
        el:$("#app-view"),
        initialize:function(){
            _.bindAll(this,"cancel");
        },
    
        events:{
            "click .button":"do"
        },
    
        do:_.once(function(){
            console.log("do something...");
        })
    });
    var view = new AppView();
    

    underscore.js once function ensures that the wrapped function can only be called once.

    0 讨论(0)
  • 2020-12-25 09:07

    The reason it doesn't work is that Backbonejs doesn't bind the event on the DOM Element .button itself. It delegates the event like this:

    $(this.el).delegate('.button', 'click', yourCallback);
    

    (docs: http://api.jquery.com/delegate)

    You have to undelegate the event like this:

    $(this.el).undelegate('.button', 'click');
    

    (docs: http://api.jquery.com/undelegate)

    So your code should look like:

    var AppView = Backbone.View.extend({
        el:$("#app-view"),
        initialize:function(){
            _.bindAll(this,"cancel");
        },
    
        events:{
            "click .button":"cancel"
        },
    
        cancel:function(){
            console.log("do something...");
            $(this.el).undelegate('.button', 'click');
        }
    });
    var view = new AppView();
    

    Another (maybe better) way to solve this is to create a state attribute like this.isCancelable now everytime the cancel function is called you check if this.isCancelable is set to true, if yes you proceed your action and set this.isCancelable to false.

    Another button could reactivate the cancel button by setting this.isCancelable to true without binding/unbinding the click event.

    0 讨论(0)
  • 2020-12-25 09:09

    There is an even easier way, assuming you want to undelegate all events:

    this.undelegateEvents();
    
    0 讨论(0)
  • 2020-12-25 09:10

    you can simply use object.off, the code below is work for me

    initialize:function () {
    
        _.bindAll(this, 'render', 'mouseover', 'mouseout', 'delete', 'dropout' , 'unbind_mouseover', 'bind_mouseover');
        .......
    
    },
    
    events: {
        'mouseover': 'mouseover',
        'unbind_mouseover': 'unbind_mouseover',
        'bind_mouseover': 'bind_mouseover',
        .....
    },
    
    mouseover: function(){
        $(this.el).addClass('hover');
        this.$('.popout').show();
    },
    
    unbind_mouseover: function(){
        console.log('unbind_mouseover');
        $(this.el).off('mouseover');
    },
    bind_mouseover: function(){
        ........
    },
    
    0 讨论(0)
  • 2020-12-25 09:13

    I like bradgonesurfing answer. However I came across a problem using the _.once approach when multiple instances of the View are created. Namely that _.once would restrict the function to be called only once for all objects of that type i.e. the restriction was at the class level rather than instance level.

    I handled the problem this way:

    App.Views.MyListItem = Backbone.View.extend({
      events: {
        'click a.delete' : 'onDelete'
      },
    
      initialize: function() {
        _.bindAll(this);
        this.deleteMe = _.once(this.triggerDelete);
      },
    
      // can only be called once
      triggerDelete: function() {
        console.log("triggerDelete");
        // do stuff
      },
    
      onDelete:(function (e) {
        e.preventDefault();
        this.deleteMe();
      })
    });
    

    Hopefully this will help someone

    0 讨论(0)
提交回复
热议问题