7

Mi sto tirando i capelli, non riesco a far funzionare gli eventi del mouse sulla mia vista backbone dopo che la vista è stata rieseguita a meno che non faccia la cosa più ridicola:gli eventi di visualizzazione backbone non funzionano dopo il re-rendering

$("a").die().unbind().live("mousedown",this.switchtabs); 

realtà ho avuto questo in là, ma ha deciso di aggiornare all'ultima spina dorsale e provare a utilizzare la nuova funzione delegateEvents().

Ecco il modo in cui il mio progetto id strutturato:

Appview/AppRouter 
    | 
    ----->PageCollection 
      | 
      ------->PageView/PageModel 
      ------->PageView/PageModel  these page view/models are not rendered 
      ------->PageView/PageModel 
      | 
      ------->PageView/PageModel 
         | 
         ----->render()  *when a pageview is rendered* 
           | 
           -----> Creates new 
            Tabcollection 
             | 
             --->TabModel/TabView <-- this is where the issue is 

Quello che succede è che il tabcollection ha una visualizzazione a scheda principale per gestire tutte le schede, quindi crea un nuovo modello/vista per ogni scheda e mette un ascoltatore per ri-renderizzare il tabview ogni volta che viene caricata una scheda. Se la tabview viene nuovamente sottoposta a rendering, nessun evento del mouse funziona più a meno che non inserisca l'istruzione jQuery contrived in quel punto.

Heres la visualizzazione a scheda e rendere (ive messo a nudo giù un bel po ')

var TabPanelView = Backbone.View.extend({ 
    className:  "tabpanel", 
    html:   'no content', 
    model:   null, 
    rendered:  false, 
    events:{ 
     'click a.tab-nav': 'switchtabs' 
    }, 
    initialize: function(args) 
    { 
     this.nav   = $("<ol/>"); 
     this.views   = args.items; 
     this.className  = args.classname?args.classname:"tabpanel"; 
     this.id    = args.id; 
     this.container  = $("<section>").attr("class",this.className).attr("id",this.id); 
     _.bindAll(this); 
     return this.el 
    }, 
    /* 
    This render happens multiple times, the first time it just puts an empty html structure in place 
    waiting for each of the sub models/views to load in (one per tab) 
    */ 
    render: function(args){ 
     if(!args) 
     { 
      //first render 
      var nav    = $("<aside/>").addClass("tab-navigation").append("<ol/>").attr("role","navigation"); 
      var tabcontent  = $("<section/>").addClass("tab-panels"); 
      for(i = 0;i<this.views.length;i++) 
      { 
       $("ol",nav).append("<li><a rel='"+this.views[i].id+"' href='javascript:;' class='tab-nav'></a></li>"); 
       tabcontent.append(this.views[i].el); 
      } 
      this.$el.empty().append(nav).append(tabcontent); 
     } 
     else if(args && args.update == true){ 
      // partial render -- i.e. update happened inside of child objects 
      var targetid = args.what.cid; 
      for(i = 0;i<this.views.length;i++) 
      { 
       var curcontent = this.$el.find("div#"+this.views[i].id); 
       var curlink  = this.$el.find("a[rel='"+this.views[i].id+"']") 
       if(this.views[i].cid == targetid) 
       { 
        curcontent.html($(this.views[i].el).html()); 
        curlink.text(this.views[i].model.rawdata.header); 
       } 
       if(i>0) 
       { 
        // set the first panel 
        curcontent.addClass("tab-content-hide"); 
       } 
       if(i==0) 
       { 
        curcontent.addClass("tab-content-show"); 
        curlink.addClass("tab-nav-selected"); 
       } 
       // this ridiculous piece of jQuery is the *ONLY* this i've found that works 
       //$("a[rel='"+this.views[i].id+"']").die().unbind().live("mousedown",this.switchtabs); 
      } 
     } 
     this.delegateEvents(); 
     return this; 
    }, 
    switchtabs: function(args){ 

     var tabTarget = args.target?args.target:false 
     if(tabTarget) 
     { 
      this.$el.find("aside.tab-navigation a").each(function(a,b) 
      { 
       $(this).removeClass("tab-nav-selected") 
      }) 
      $(tabTarget).addClass("tab-nav-selected"); 
      this.$el.find("div.tab-content-show").removeClass("tab-content-show").addClass("tab-content-hide"); 
      this.$el.find("div#"+tabTarget.rel).removeClass("tab-content-hide").addClass("tab-content-show"); 
     } 
    } 
}); 

Qualcuno può pensare a perché eventi spina dorsale del mouse semplicemente non sparano a tutti, è vero, perché non sono sul DOM ? Ho pensato che fosse la spina dorsale particolarmente utile? ...

+0

Quali passi hai seguito per risolvere questo problema fino ad ora? Un paio di cose che vorrei provare: vedere se è possibile impostare un punto di interruzione nell'origine Backbone in cui viene elaborato l'elemento 'events'. Potresti darti qualche idea. Prova inoltre a utilizzare i punti di interruzione DOM e Event Listener di Chrome. Questo potrebbe aiutarti a controllare se un codice viene eseguito o se gli eventi non riescono a collegarsi. –

+0

Ive ha eseguito l'accesso a jq $ (document) .find ("tab-nav-selected") per vedere se gli oggetti renderizzati sono effettivamente sul dom .. bene ottenere i risultati corretti. sono passati attraverso i punti di interruzione, nel mio codice. Non sono abbastanza fiducioso da farlo scavare nel backbone stesso con il debugger. tutto sembra a posto ... Non sono certo, ma sembra che gli eventi vengano sovrascritti a causa del re-rendering o ... ummm – Alex

risposta

6

Questa riga di codice è probabile che il vostro problema:

this.delegateEvents();

Rimuovere quello e dovrebbe funzionare.

L'unica volta che è necessario chiamare lo delegateEvents da soli, è quando si verificano eventi dichiarati separatamente dall'hash events della vista. La vista Backbone chiamerà questo metodo per te quando crei un'istanza della vista.

+0

purtroppo nessun dado. onorato di averti risposto, ho letto un sacco di utili elementi di backbone sul tuo blog. Ho ceduto e andato con jQuery.live ... sì, è un abominio .. ma è l'unica cosa che funziona e ho 2 giorni fino alla scadenza .. humm – Alex

2

Quando la vista viene rieseguita, stai riutilizzando la stessa vista e stai richiamando semplicemente il rendering(), oppure stai cancellando la vista e creando una visione completamente nuova?

In entrambi i casi, sembra che la causa è che gli eventi di visualizzazione non vengono liberati prima che la vista venga nuovamente sottoposta a rendering. Derick Bailey ha un ottimo post su questo.

Quando si ri-renderizzare, 1) assicurarsi di non associare tutti gli eventi nella vecchia visione e 2) creare una nuova vista e rendono

+0

bel articolo, ma non posso andare a fare nuove viste genitore quando ogni bambino visualizza gli aggiornamenti (la vista genitore deve rispondere alla vista figlio). Stranamente ho provato il metodo nell'articolo tuttavia stranamente funziona circa 1 su 3 volte ho ricaricato la pagina le altre volte ... niente – Alex

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.

+1

@Alex Nel tuo codice prova: '' questo . $ el.children(). detach(). append (nav) .append (tabcontent); '' e dovrebbe ** funzionare ** perfettamente. Non è necessario ricreare un'istanza della vista. – AmpT

+0

Vedere queste risposte come ulteriore riferimento: http://stackoverflow.com/a/12029250/2728686 e http://stackoverflow.com/a/7417078/2728686 – AmpT

Problemi correlati