Backbone.js View не может отменить события должным образом

У меня есть код Backbone.js, который привязывает событие click к кнопке, и я хочу отменить его после нажатия, пример кода, как показано ниже:

var AppView = Backbone.View.extend({
    el:$("#app-view"),
    initialize:function(){
        _.bindAll(this,"cancel");
    },

    events:{
        "click .button":"cancel"
    },

    cancel:function(){
        console.log("do something...");
        this.$(".button").unbind("click");
    }
});
var view = new AppView();

Однако unbind не работает, я попробовал несколько разных способов и завершил привязку события к инициализации функции с помощью jQuery, но не в модели Backbone.events.

Кто-нибудь знает, почему unbind не работает?

Ответ 1

Причина, по которой он не работает, заключается в том, что Backbonejs не связывает событие с самим элементом DOM Element. Он делегирует событие следующим образом:

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

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

Вам нужно отключить событие следующим образом:

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

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

Итак, ваш код должен выглядеть так:

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();

Другим (возможно, лучшим) способом решения этого является создание атрибута состояния, такого как this.isCancelable, теперь каждый раз, когда вызывается функция cancel, вы проверяете, установлено ли значение this.isCancelable true, если да, вы выполните свое действие и установите this.isCancelable в значение false.

Другая кнопка может повторно активировать кнопку отмены, установив this.isCancelable в значение true без привязки/открепления события клика.

Ответ 2

Вы могли бы решить этот другой способ

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 однажды гарантирует, что завернутая функция может быть вызван только один раз.

Ответ 3

Существует еще более простой способ, предполагая, что вы хотите отменить все события:

this.undelegateEvents();

Ответ 4

Мне нравится bradgonesurfing ответ. Однако я столкнулся с проблемой, использующей подход _.once, когда создаются несколько экземпляров представления. А именно, что _.once ограничил бы функцию, которая будет вызываться только один раз для всех объектов этого типа, то есть ограничение было на уровне класса, а не на уровне экземпляра.

Я обработал проблему следующим образом:

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();
  })
});

Надеюсь, это поможет кому-то

Ответ 5

вы можете просто использовать object.off, код ниже работает для меня

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(){
    ........
},