2011-07-26 11 views
11

Tengo algo de código Backbone.js que se unen a un evento de clic de un botón, y quiero desvincularla después se hace clic, el ejemplo de código de la siguiente manera:Backbone.js Vista no puede desvincular eventos adecuadamente

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

Sin embargo, la desvinculación no funciona, probé varias formas diferentes y terminé vinculando eventos en la función de inicialización con jQuery pero no en el modelo Backbone.events.

¿Alguien sabe por qué la desvinculación no está funcionando?

Respuesta

37

El motivo por el que no funciona es que Backbonejs no vincula el evento en el botón DOM Element. Que delegue este evento como este:

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

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

Tienes que undelegate el evento como este:

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

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

Por lo que su el código debería verse así:

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

Otra forma (mejor) de resolver esto es crear un atributo de estado como this.isCancelable ahora cada vez que se llama a la función cancel marque si this.isCancelable se establece en verdadero, si es así, proceda con su acción y establezca this.isCancelable en falso.

Otro botón podría reactivar el botón de cancelación configurando this.isCancelable en verdadero sin vincular/desvincular el evento de clic.

17

Usted podría resolver esto de otra manera

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 vez función asegura que la función envuelta sólo puede ser llamado una vez.

+1

Me gusta de esta manera mejor que tener que recuperar el evento. Mucho más simple y más limpio, gracias por esto. –

+0

Gracias por este consejo. – v1r00z

2

Me gusta bradgonesurfing answer. Sin embargo, encontré un problema con el enfoque _.once cuando se crean varias instancias de la Vista. A saber, _.once restringiría que la función se llame solo una vez para todos los objetos de ese tipo, es decir, la restricción estaba en el nivel de clase en lugar del nivel de instancia.

que maneja el problema de esta manera:

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

Esperamos que esto ayude a alguien

+0

Tuve un problema donde mi equivalente de esto.triggerDelete estaba disparando al inicializar. Tal vez el modelo de evento ha cambiado en Underscore un poco desde esta respuesta. En cualquier caso, lo arreglé modificando ese código de inicialización a: 'this.deleteMe = _.once (function() {this.triggerDelete;});' – Matt

1

puede simplemente usar object.off, el código de abajo es un trabajo para mí

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

Hay un aún más fácil, suponiendo que desea restablecer todos los eventos:

this.undelegateEvents(); 
+1

¡Guau! he estado buscando esto por muchos días –

Cuestiones relacionadas