2011-10-04 14 views
7

Estoy dando vueltas en círculos y aparentemente me falta algo en mi aplicación actual que implementa backbone.js. El problema es que tengo un AppView maestro, que inicializa varias subvistas (un gráfico, una tabla de información, etc.) para la página. Mi deseo es poder cambiar el diseño de la página dependiendo de un indicador de parámetro que se transmita mientras se navega.Jerarquización de la vista de red troncal

Lo que encuentro es un caso en el que las subvistas, que hacen referencia a elementos dom que estarían en su lugar después de la plantilla, no tienen acceso a esos elementos durante el proceso principal de inicialización de AppView. Entonces, la pregunta principal es, ¿cómo me aseguro de que los elementos Dom apropiados estén en su lugar para que cada proceso de enlace de evento se configure correctamente?

Con el siguiente código si tengo un evento vinculado a un cambio de modelo en mi LayoutView, el diseño se procesa pero las vistas siguientes no se representan correctamente. Algo con lo que he tropezado ha sido establecer todos los valores '.el' de las vistas en un elemento estático dentro de la estructura html. Esto hace que el renderizado ocurra, aunque parece que se aleja de la buena capacidad de alcance proporcionada al utilizar '.el'.

Código de ejemplo:

//Wrapped in jquery.ready() function... 
//View Code 
GraphView = Backbone.View.extend({ // init, model bind, template, supporting functions}); 

TableView = Backbone.View.extend({ // init, model bind, template, supporting functions}); 

LayoutView = Backbone.view.extend({ 
    initialize: function() { 
    this.model.bind('change:version', this.render, this); 
    }, 
    templateA = _.template($('#main-template').html()), 
    templateB = _.template($('#secondary-template').html()), 
    render: function() { 
    if ('main' == this.model.get('version')) { 
     this.el.html(this.templateA()); 
    } else { 
     this.el.html(this.templateB()); 
    } 
    }, 
}); 

MainView = Backbone.View.extend({ 
    initialize: function() { 
    this.layoutView = new LayoutView({ 
     el: $('#layoutContainer'), 
     model: layout, 
    }); 
    this.graphView = new GraphView({ 
     el: $('.graphContainer'), 
     model: graph 
    }); 
    this.tableView = new TableView({ 
     el: $('#dataTableContainer', 
     model: dataSet 
    }); 
    }, 
}); 

// Model Code 
Layout = Backbone.Model.extend({ 
    defaults: { 
    version: 'main', 
    }, 
}); 

Graph = Backbone.Model.extend({}); 
dataSet = Backbone.Model.extend({}); 

// Router code... 

// Fire off the app 
AppView = new MainView($('#appContainer')); 
// Create route, start up backbone history 

HTML: Por simplicidad solo reordena los divs entre los dos diseños.

<html> 
    <head> 
    <!-- include above js and backbone dependancies --> 
    </head> 
    <body> 
    <script type="text/template" id="main-template"> 
     <div class="graphContainer"></div> 
     <div class="dataTableContainer"></div> 
     <div>Some other stuff to identify that it's the main template</div> 
    </script> 
    <script type="text/template" id="secondary-template"> 
     <div class="dataTableContainer"></div> 
     <div>Rock on layout version two!</div> 
     <div class="graphContainer"></div> 
    </script> 
    <div id="appContainer"> 
     <div id="nav"> 
     <a href="#layout/main">See Layout One</a> 
     <a href="#layout/secondary">See Layout Two</a> 
     </div> 
     <div id="layoutContainer"></div> 
    </div> 
    </body> 
</html> 

Apreciar la información/aportes que cualquiera de ustedes pueda tener. ¡Gracias!

+0

Solo para tu información, tienes un montón de errores ortográficos en tu código. ¿Es seguro asumir que estos son problemas de copiar/pegar, no errores de sintaxis reales? – nrabinowitz

+0

Blame copy/paste, la lógica subyacente, con suerte todavía se transmite. Gracias por señalar eso. – aztechy

Respuesta

8

Tiene un código faltante en su muestra, pero si entiendo correctamente, el problema es que está tratando de representar las vistas que dependen de HTML generado por LayoutView, pero el diseño se elige de forma asíncrona cuando el el modelo se ha actualizado, por lo que LayoutView no se ha procesado todavía.

hay (al igual que con más o menos relacionados con Backbone-todo) varios enfoques para esto, pero en general:

  • Si tengo vistas que dependen de un "padre" que se queden vista, me quedo asigne la responsabilidad de instanciar y representar esas vistas en la vista principal; en este caso, LayoutView, no MainView.

  • Si el padre se está representando de forma asíncrona, debe realizar esa instanciación en la devolución de llamada; aquí, el método LayoutView.render().

por lo que podría estructurar el código como el siguiente:

LayoutView = Backbone.view.extend({ 
    initialize: function() { 
    this.model.bind('change:version', this.render, this); 
    // you probably want to call this.model.fetch() here, right? 
    }, 
    templateA: _.template($('#main-template').html()), 
    templateB: _.template($('#secondary-template').html()), 
    render: function() { 
    if ('main' == this.model.get('version')) { 
     this.el.html(this.templateA()); 
    } else { 
     this.el.html(this.templateB()); 
    } 
    // now instantiate and render subviews 
    this.graphView = new GraphView({ 
     // note that I'm using this.$ to help scope the element 
     el: this.$('.graphContainer'), 
     model: graph 
    }); 
    this.tableView = new TableView({ 
     el: this.$('.dataTableContainer'), 
     model: dataSet 
    }); 
    // you probably need to call graphView.render() 
    // and tableView.render(), unless you do that 
    // in their initialize() functions 
    }, 
}); 

Tenga en cuenta que usted no tiene que pasar en un el en instanciación - se puede crear una instancia subvistas en initialize(), y establece la propiedad el en subview.render(). Incluso puede crear instancias en MainView.initialize(), como lo hace ahora, y pasar las vistas al LayoutView para hacerlas de forma asíncrona. Pero creo que el enfoque anterior es probablemente más limpio.

+0

Gracias por la respuesta.Jugué con esta implementación de llamar a las subvistas dentro de LayoutView después del proceso de renderizado. Tiene razón al suponer que las diversas subvistas tienen su propio procesamiento, que se actualizan en los estados de cambio del modelo. Por alguna razón extraña, aunque parecía que después de mi búsqueda, algunas llamadas de representación se estaban llamando varias veces. Dispararme para pensar que estaba agregando ineficazmente las diversas subvistas varias veces. Supongo que tendré que rastrear qué más puede estar causando las múltiples llamadas de renderización después de recuperar mis datos. ¡Gracias de nuevo! – aztechy

+0

Me alegro de que esto haya ayudado: a menudo me parece que necesito lógica para crear una instancia de una subvista solo si no está cargada, lo que podría ser el problema. (Por cierto, si le gusta la respuesta, puede aprobar presionando la marca de verificación a la izquierda :) – nrabinowitz

+0

Derecha, se necesita crear lógica para crear una instancia de la subvista. Lamentablemente, me encuentro con un problema por el cual la creación de instancias de las subvistas dentro del layoutView.render() está causando que las subvistas que introducen cambios en el modelo, definidas en su configuración de inicialización, no se procesen correctamente. Principalmente en el caso en que el estado del modelo de una vista permanece igual en la navegación, esa subvista en particular parece sobrescribirse con una plantilla vacía debido al proceso anterior. Estoy pensando que esto puede requerir volver a trabajar la lógica del evento. – aztechy

Cuestiones relacionadas