7

Me estoy tirando de pelos, parece que no puedo obtener eventos de mouse para trabajar en mi vista de red troncal después de volver a hacer la vista a menos que haga lo más ridículo:los eventos de la vista de red troncal no funcionan después de volver a renderizar

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

en realidad tenía esto en allí, pero decidió actualizar a la última columna vertebral y tratar de utilizar la nueva función delegateEvents().

Aquí es la forma en que mi Identificación del proyecto estructurado:

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 

Lo que sucede es que el tabcollection tiene una TabView principal para gestionar todas las fichas, a continuación, crea un nuevo modelo/vista para cada ficha y pone una oyente para volver a procesar la pestaña cuando se carga una pestaña. Si la pestaña se vuelve a representar, ya no funcionan los eventos del mouse a menos que coloque esa declaración jQuery artificial allí.

Heres la TabView y render (ive despojado abajo un poco)

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

Puede alguien pensar en qué eventos espina dorsal del ratón simplemente no se activan en absoluto, es porque no están en el DOM ? Pensé que era aquí donde la red troncal era particularmente útil? ...

+0

¿Qué pasos ha seguido para solucionar este problema hasta el momento? Un par de cosas que probaría: vea si puede establecer un punto de interrupción en el origen de Backbone donde se procesa el elemento 'events'. Podría darte una idea. Además, intente utilizar los puntos de interrupción de DOM y Event Listener de Chrome. Esto podría ayudarlo a verificar si algún código se está ejecutando o si los eventos simplemente no se pueden conectar. –

+0

He registrado contra jq $ (document) .find ("tab-nav-selected") para ver si los elementos renderizados están realmente en el dom .. fin de obtener los resultados correctos. han pasado por puntos de interrupción, en mi propio código. No estoy lo suficientemente seguro como para ir a cavar en la red troncal con el depurador. el alcance parece todo bien ... No estoy seguro de ningún modo, pero parece que los eventos se sobrescriben debido a la re-interpretación o ... ummm – Alex

Respuesta

6

Esta línea de código probable que su problema:

this.delegateEvents();

Quitar eso y debería funcionar.

La única vez que necesita llamar al delegateEvents es cuando tiene eventos que están declarados por separado del hash events de su vista. La vista de Backbone llamará a este método cuando cree una instancia de la vista.

+0

lamentablemente no había dado. honrado de tener tu respuesta, he leído un montón de cosas útiles en tu blog. He cedido y se ha ido con jQuery.live ... sí, es una abominación ... pero es lo único que funciona y tengo 2 días para la fecha límite ... humm – Alex

2

Cuando la vista se vuelve a representar, ¿está reutilizando la misma vista y simplemente llamando de nuevo a render(), o está eliminando la vista y creando una vista completamente nueva?

De cualquier forma, parece que la causa es que los eventos de la vista no se desenlazan antes de volver a generar la vista. Derick Bailey tiene un gran post sobre esto.

Al volver a hacer, 1) asegurarse de que se desvincula todos los eventos en el antiguo punto de vista y 2) crear un nuevo punto de vista y la hacen

+0

buen artículo sin embargo, no puedo ir haciendo nuevas vistas de padres cuando cada hijo ve actualizaciones (la vista principal debe responder a la vista secundaria). Curiosamente, probé el método en el artículo, aunque curiosamente funcionaba aproximadamente 1 de cada 3 veces, volví a cargar la página el resto de las veces ... nada – Alex

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.

+1

@Alex En tu código, intenta: '' this . $ el.children(). detach() .adpend (nav) .append (tabcontent); '' y debería ** funcionar ** a la perfección. No es necesario volver a crear una instancia de la vista. – AmpT

+0

Consulte estas respuestas como referencia adicional: http://stackoverflow.com/a/12029250/2728686 y http://stackoverflow.com/a/7417078/2728686 – AmpT

Cuestiones relacionadas