2011-10-19 16 views
11

Creo que no entiendo muy bien la idea detrás del uso correcto de los enrutadores troncales. Esto es lo que tengo:Enrutadores centrales: aguarde a que se obtengan los datos primero

Tengo algunos datos que obtengo del servidor cuando se carga la página y luego los comparto en modelos y colecciones. El número de esos modelos y colecciones es indefinido. Quiero usar el enrutador para poder representar la vista de determinada colección directamente desde el principio.

El problema es: el enrutador de Backbone se inicia temprano, y como le pido que acceda a una determinada vista y active su acción render, no puede hacer eso, porque esas vistas aún no se han creado. Eso significa que en realidad tengo que hacer que mis rutas comiencen después de que se complete la búsqueda.

No sé si esto es una forma correcta de hacerlo, pero la única idea que se me ocurrió es que:

  1. Wrap la definición de rutas y el bit Backbone.history.start(); en un nivel superior separada -accesible (es decir, prepárese para llamarlo manualmente más tarde).
  2. Run que funcionan como la devolución de llamada success para la de mis colecciones fetch()
  3. El número de esas colecciones se desconoce, también tengo ninguna manera de saber cuándo todos ellos han sido extraídas, y yo no quiero iniciar el rutas más de una vez. Así que hago uso de _.defer() y _.once().

Esto funciona, pero seguro que se ve muy raro:

Routers:

window.startRoutes = _.once(function() { 

     var AccountPage = Backbone.Router.extend({ 

      routes: { 
      'set/:id': 'renderSet', 
      }, 

      renderSet: function(setId) { 

       /** … **/ 

       // Call the rendering method on the respective CardView 
       CardsViews[setId].render(); 

      } 

     }); 

     var AccountPageRouter = new AccountPage; 

     Backbone.history.start(); 

    }); 

Colección:

window.CardsCollection = Backbone.Collection.extend({ 

    model: Card, 

    initialize: function(params) { 

     /** … **/ 

     // Get the initial data 
     this.fetch({success: function() { 
      _.defer(startRoutes); 
     }}); 

    }, 

}); 

Así que mi pregunta es ... estoy haciendo lo correcto? ¿O hay una mejor manera de hacer esto (debe ser)?

+0

¿Por qué hacer una llamada ajax inmediatamente? ¿Por qué no simplemente renderizar la página con el json requerido para la carga de datos inicial y pasar los datos al inicio de la red troncal? – redsquare

Respuesta

14

Puede definir su enrutador antes de tiempo; no hará nada hasta que llame a Backbone.History.start().

puede enlazar el evento "reset" en su colección para comenzar la historia de esta manera:

my_collection.bind("reset", _.once(Backbone.History.start, Backbone.History)) 

A continuación, el router empezar a hacer cosas cuando su colección está totalmente cargado. No estoy seguro de si esto es exactamente lo que está buscando (ya que mencionó tener un número variable de colecciones).

Tengo una situación similar, excepto que sé de antemano qué colecciones quiero cargar antes de comenzar el enrutamiento.He añadido un método startAfter a mi router, así:

window.Workspace = new (Backbone.Router.extend({ 
    . . . 
    startAfter: function(collections) { 
     // Start history when required collections are loaded 
     var start = _.after(collections.length, _.once(function(){ 
     Backbone.history.start() 
     })) 
     _.each(collections, function(collection) { 
     collection.bind('reset', start, Backbone.history) 
     }); 
    } 
    })); 

y después he fijado mis colecciones

Workspace.startAfter([collection_a, collection_b, ...]) 

Esto podría ser adaptado para trabajar con modelos independientes también, aunque creo que se Tendría que vincularse a algo que no sea el evento de "reinicio".

Me complace haber leído su código de ejemplo, el uso de _.once y _.defer me indicó la dirección correcta.

+0

¿No es 'my_collection.bind (" reset ", _.once (Backbone.history.start))'? – iblue

+2

Usó argumentos incorrectos para '_.once()'. Editaré tu respuesta para arreglar esto. kthxbye :) – iblue

+0

El ejemplo '_.once()' no funcionó para mí. Tuve que usar: 'app.users.on (" reset ", _.once (function() { Backbone.history.start(); }));' –

1

Estoy comprobando mi método .render() que todos los campos obligatorios se llenan antes de usarlo. Si aún no está lleno, estoy procesando un widget 'Loading ...'.

Y todos mis puntos de vista están suscritos a los cambios del modelo, por this.model.bind('change', this.render, this);, por lo que justo después de que se cargue el modelo, se volverá a llamar render().

Cuestiones relacionadas