2011-09-08 14 views
24

[EDITAR: Solucioné el problema anterior llamando a delegateEvents(), pero no debería tener que hacerlo. Volviendo a publicar w/más información.]backbone.js eventos que no se activan después de volver a procesar

Tengo una vista que cuando se procesa tiene un botón de inicio de sesión con un evento de clic adjunto. Primero renderice todos los trabajos: haga clic en el botón y cuando la llamada ajax sea exitosa, las indicaciones de inicio de sesión desaparecerán y se mostrará la vista de bienvenida (LoggedInView). Pero, si navego de regreso a esta Vista más tarde (#foo) la UI se renderiza pero la asociación de eventos se ha ido sin forzar manualmente el problema llamando a delegateEents().

¿Qué pasó que mis eventos no se volvieron a asociar?

LoginView = Backbone.View.extend({ 
    template: _.template($("#loginTemplate").html()), 
    initialize: function(stuff,router) { 
     _.bindAll(this,'render','rc','gotProfile'); 
     this.model.bind("rc",this.rc) 
     this.router = router; 
    }, 
    events: { 
     'click .loginButton': 'login' 
    }, 
    render: function() { 
     $(this.el).html(this.template(this.model.toJSON())); 
     $(this.el).find(".actionButton").button(); // Button 
//  this.delegateEvents(this.events); // NEEDED! Re-wire events on re-render 
     return this; 
    }, 
    rc: function(code) { 
     switch(code) { 
      case errCodes.USER_NOT_FOUND: this.notFound(); break; 
      case errCodes.OK:    this.loginOk(); break; 
      default:       this.otherErr(); break; 
     } 
    }, 
    login: function() { 
     clearErrors($('[rel="req"]')); 
     var okReq = validate($('#login [rel="req"]'), validateReq); 
     var okEmail = validate([$('#uid')], validateEmail); 
     if(okReq && okEmail) { 
      this.model.set({'uid':$('#uid').val().trim(),  'pwd':$('#pwd').val().trim()}); 
      this.model.fetch(); 
     } 
    }, 
    notFound: function() { 
     validate([$('#uid'),$('#pwd')], function(){return[false,"Invalid user/password"]}); 
    }, 
    otherErr: function() { 
     validate([$('#uid'),$('#pwd')], function(){return[false,"Please contact support for help logging in."]}); 
    }, 
    loginOk: function() { 
     this.profile = new Profile({uid:this.model.get('uid'),token:this.model.get('key')}); 
     this.profile.bind("rc",this.gotProfile) 
     this.profile.fetch(); 
    }, 
    gotProfile: function() { 
     this.router.navigate('/',true); 
    } 
}); 

LoggedInView = Backbone.View.extend({ 
    template: _.template($("#loggedInTemplate").html()), 
    uList: new ProfileList(), 
    initialize: function() { 
     _.bindAll(this,'render','renderUserList','renderUser'); 
     this.model.bind('show', this.render); 
     this.uList.bind('rc', this.render); 
    }, 
    events: { 
     'click #ufa': 'getUsersForHouse' 
    }, 
    render: function() { 
     $(this.el).html(this.template(this.model.toJSON())); 
     this.renderUserList(); 
//  this.delegateEvents(this.events); // NEEDED! Re-wire events on re-render 
     return this; 
    }, 
    renderUserList: function() { 
     $(this.el).find('ul').empty(); 
     this.uList.each(this.renderUser); 
    }, 
    renderUser: function(aUser) { 
     $(this.el).find('#userList').append("<li>"+aUser.get('person').firstName+"</li>"); 
    }, 
    getUsersForHouse: function() { 
     this.uList.fetch(this.model.get('token'),"house"); 
    } 
}); 

Main = Backbone.Router.extend({ 
    routes: { 
     'foo': 'foo', 
     '*all': 'home' 
    }, 
    initialize: function() { 
     this.token = new Token(); 
     this.loginView = new LoginView({model:this.token},this); 
    }, 
    foo: function(){ // naving here looses click event on login button 
     $('#login').empty(); 
     $("#login").append(this.loginView.render().el); 
    }, 
    home: function() { 
     $('#login').empty(); 
     if(this.loginView.profile == null) 
      $("#login").append(this.loginView.render().el); 
     else { 
      this.loggedInView = new LoggedInView({model:this.loginView.profile}); 
      $("#login").append(this.loggedInView.render().el); 
     } 
    } 
}); 
+0

necesita proporcionar más información para saber qué está pasando y por qué. ¿Puedes publicar más código de tu vista y el código de tu enrutador? –

+0

Aquí está mi router y Ver afectada: main = {(Backbone.Router.extend \t rutas: { \t \t '': 'casa', \t \t 'bien': 'loggedin' \t}, \t initialize: function() { \t \t this.token = new Token(); \t \t this.loginView = new LoginView ({modelo: this.token}, this); \t}, \t casa: function() { \t \t $ ('# login'). Empty(); \t \t $ ("# login"). Append (this.loginView.render(). El); \t}, \t loggedin: function() { \t \t this.loggedInView = new LoggedInView ({modelo: this.loginView.profile}); \t \t $ ('# login'). Empty(); \t \t $ ("# login"). Append (this.loggedInView.render(). El); \t} }); – Greg

+0

No puedo agregar la Vista: demasiado grande para que acepte este editor. El LoginView tiene la cláusula de eventos. – Greg

Respuesta

18

Vacias el the #login div. A medida que el doc jQuery dice:

Para evitar pérdidas de memoria, jQuery elimina otras construcciones tales como datos y controladores de eventos de los elementos secundarios antes de retirar las propios elementos.

Por lo tanto, está eliminando eventos de sus vistas. Prefiero usar separar porque guarda eventos. http://api.jquery.com/detach/

Puede implementar un mostrar/ocultar en sus vistas que se ocupará de esto.

+1

que has guardado me salvó HORAS! – tmimicus

1

Estoy enfrentando el mismo problema. La forma en que lo resolví por ahora es volver a instanciar por completo el objeto Ver con new MyView(), esto asegura que los eventos se recuperen.

Espero que ayude?

2

Encontré una solución a esto, porque estaba teniendo el mismo problema, en realidad detach() no es la solución porque devolverá los viejos elementos DOM que no son útiles.

esto es lo que hay que hacer

render: function(){ this.$el.empty(); ...... this.$el.appendTo($DOM); } 

si se utiliza el método .html() sus eventos no dispararán. necesita adjuntar el código HTML recién creado al DOM, utilizando appendTo().

Por cierto, esto solo me ha pasado si está utilizando tagName y className para construir su vista de forma dinámica.

1

Al utilizar $(el).empty() que elimina todos los elementos secundarios del elemento seleccionado y elimina todos los los eventos (y datos) que son ligado a ninguna (niño) elementos interior del elemento seleccionado (el).

Para mantener los acontecimientos ligados a los elementos secundarios, pero aún así eliminar los elementos secundarios, el uso:

$(el).children().detach(); en lugar de $(.el).empty();

Esto permitirá a su fin de reRender con éxito con los eventos todavía atado y trabajando.

+0

Consulte lo siguiente para obtener más información: http://stackoverflow.com/a/12029250/2728686 y http://www.jquerybyexample.net/2012/05/empty-vs-remove-vs-detach-jquery.html – AmpT

Cuestiones relacionadas