2011-09-08 16 views
24

[EDIT: ho risolto il problema in precedenza chiamando delegateEvents(), ma non dovevo farlo. Re-posting w/maggiori informazioni.]eventi backbone.js non attivati ​​dopo il re-rendering

Ho una vista che quando il rendering ha un pulsante di accesso su di esso con un evento click allegato. Per prima cosa esegui il rendering di tutti i lavori: fai clic sul pulsante e al termine della chiamata ajax i messaggi di accesso scompaiono e viene visualizzata la vista di benvenuto (LoggedInView). Tuttavia, se torno a questa vista in un secondo momento (#foo) il rendering dell'interfaccia utente viene rimosso, ma l'associazione eventi non funziona senza forzare manualmente il problema chiamando delegateEents().

Che cosa è successo che i miei eventi non si sono riassociati?

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

è necessario fornire ulteriori informazioni per sapere cosa sta succedendo e perché. puoi pubblicare più codice della tua vista e il tuo codice router? –

+0

Ecco il mio router e interessata Vista: main = Backbone.Router.extend ({ \t percorsi: { \t \t '': 'casa', \t \t 'ok': 'loggedin' \t}, \t initialize: function() { \t \t this.token = nuovo token(); \t \t this.loginView = new LoginView ({modello: 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 ({modello: this.loginView.profile}); \t \t $ ('# login'). Empty(); \t \t $ ("# login"). Append (this.loggedInView.render(). El); \t} }); – Greg

+0

Non riesco ad aggiungere la vista, troppo grande per essere accettata da questo editor. LoginView ha la clausola di eventi. – Greg

risposta

18

Si svuota il #login div. Come il doc jQuery dice:

Per evitare perdite di memoria, jQuery rimuove altri costrutti quali dati e gestori di eventi dagli elementi figlio prima di togliere le elementi stessi.

Così si rimuovono efficacemente gli eventi dalle viste. Preferisco usare il distacco perché mantiene gli eventi. http://api.jquery.com/detach/

È possibile implementare uno spettacolo/nascondi nelle visualizzazioni che si occuperanno di questo.

+1

salvato mi ha salvato ORE! – tmimicus

1

Sto affrontando lo stesso problema. Il modo in cui l'ho risolto per ora è una nuova istanziazione dell'oggetto View con new MyView() questo assicura che gli eventi siano in estensione.

Spero che sia d'aiuto?

2

Ho trovato una soluzione a questo, perché stavo avendo lo stesso problema, in realtà detach() non è la soluzione perché porterà indietro i vecchi elementi DOM per voi che non è utile.

questo è ciò che devi fare

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

se si utilizza il metodo .html() gli eventi non si innescherà. è necessario allegare l'HTML appena creato al DOM, usando appendTo().

dal modo in cui mi è successo solo se si sta utilizzando tagName e className per creare la vista in modo dinamico.

1

Quando si utilizza $(el).empty() rimuove tutti gli elementi figlio nell'elemento selezionato e rimuove tutti i le eventi (e dati) che sono legata a qualsiasi (bambino) elementi all'interno dell'elemento selezionato (el).

Per mantenere gli eventi legati alle gli elementi figlio , ma ancora rimuovere gli elementi figlio, l'uso:

$(el).children().detach(); invece di $(.el).empty();

Questo permetterà l'immagine per rerender con successo con gli eventi ancora legato e funzionante.

+0

Si prega di consultare quanto segue per ulteriori riferimenti: http://stackoverflow.com/a/12029250/2728686 e http://www.jquerybyexample.net/2012/05/empty-vs-remove-vs-detach-jquery.html – AmpT

Problemi correlati