meteor iron-router

Meteor Iron Router con waitOn personalizado



iron-router (2)

Me preguntaba si alguien ha construido su propia función waitOn. No estoy usando suscribirse para manejar el waitOn, sino que quiero esperar en un helper para activar el estado listo, algo como esto:

this.route(''edit_Record'', { path: ''/record/edit/:_id'', waitOn: function() { return XXXXX; } }); Template.edit_Record.helpers({ selectedRecord: function () { wait(3000); var x = myRecords.findOne({_id: this.editid}); //XXXXX This is where I want to set ''ready'' return x; } });


Diseñé mi propio patrón para trabajar con un waitOn personalizado. Debe tener en cuenta que IronRouter no renderizará su plantilla (y, por lo tanto, ninguno de sus ayudantes, excepto si los llama manualmente, lo que generalmente es impar) A MENOS que todos los identificadores especificados en la función waitOn estén listos.

waitOn es un cálculo reactivo, por lo que los identificadores que especifique deben ser fuentes de datos reactivos, y cuando su estado de listo evolucione, waitOn se volverá a evaluar automáticamente y, en última instancia, notificará a IronRouter que está bien renderizar la plantilla.

Entonces, si queremos usar waitOn con algo más que los identificadores de suscripción, tenemos que implementar nuestro propio objeto con un método reactivo ready () (esto es de los documentos). Llamaremos a este objeto "Camarero" porque su función es esperar hasta que ocurra algún evento y luego establece su estado interno en listo.

Le presentaré un ejemplo simple que resuelve un problema común: precarga de imágenes. Supongamos que tiene una plantilla que representa elementos de imagen cuyos atributos src están almacenados en una Colección: le gustaría representar la plantilla solo cuando las imágenes se cargan en el lado del cliente.

<template name="view"> <div> <h1>{{title}}</h1> <img src="{{firstImageUrl}}" /> <img src="{{secondImageUrl}}" /> </div> </template>

Se me ocurrió la siguiente interfaz:

this.route("view",{ path:"/view/:_id", loadingTemplate:"loadingTemplate", template:"view", // our Waiter object handle designed to wait until images are loaded imagePreloadingWaiter:new ImagePreloadingWaiter(), // load is called only once each time the route is triggered load:function(){ // reset our waiter this.imagePreloadingWaiter.reset(); }, // before : reactive computation that will be rerun until the route template is rendered before:function(){ // setup collection subscription var subscriptionHandle=this.subscribe("collectionById",this.params._id); if(subscriptionHandle.ready()){ // get the route data context var collection=this.data(); // collect the images URLs we want to preload var params={ images:[ collection.firstImageUrl, collection.secondImageUrl ] }; // fire the preloader this.imagePreloadingWaiter.fire(params); } }, // we specify that we want to wait on our ImagePreloadingWaiter handle waitOn:function(){ return this.imagePreloadingWaiter; }, // return the data context used by this route data:function(){ return Collection.findOne(this.params._id); } });

Al usar esta definición de ruta, mostramos la plantilla de carga hasta que finalmente se carguen las URL de las imágenes almacenadas en nuestra colección, gracias al método waitOn que espera en nuestro identificador de la interfaz ImagePreloadingWaiter.

Ok, ahora que tenemos una visión general de la interfaz que nos gustaría usar, impleméntela de hecho:

// Simple interface to use with the IronRouter waitOn method Waiter=function(){ // avoid firing the waiter multiple time in a Deps.Computation context this.isFired=false; // reactive data source : have we been waiting long enough ? this.isReady=false; this.dependency=new Deps.Dependency(); }; _.extend(Waiter.prototype,{ // reset method, clear the waiter state reset:function(){ this.isFired=false; // this.isReady=false; this.dependency.changed(); }, // reactive ready method : this is the interface needed by waitOn ready:function(){ this.dependency.depend(); return this.isReady; }, // fire the Waiter object only once before being resetted fire:function(params){ if(!this.isFired){ this.isFired=true; // this abstract method must be overloaded in child classes this.wait(params); } }, // must be called in Waiter.wait() to acknowledge we''re done waiting waitedEnough:function(){ // if we have reset the Waiter meanwhile, silently discard the notification if(this.isFired){ this.isReady=true; this.dependency.changed(); } } }); // Simple waiter that simply waits N seconds before getting ready TimeoutWaiter=function(){ Waiter.call(this); }; TimeoutWaiter.prototype=Object.create(Waiter.prototype); _.extend(TimeoutWaiter.prototype,{ wait:function(params){ var self=this; // after N seconds, notify that we are done waiting Meteor.setTimeout(function(){ self.waitedEnough(); },params.seconds*1000); } }); // Image preloader for the IronRouter ImagePreloadingWaiter=function(){ Waiter.call(this); }; ImagePreloadingWaiter.prototype=Object.create(Waiter.prototype); _.extend(ImagePreloadingWaiter.prototype,{ wait:function(params){ var self=this; // if(images.length>0){ var imageLoadedCounter=0; _.each(images,function(imageUrl){ function onImageLoadOrError(){ imageLoadedCounter++; if(imageLoadedCounter==images.length){ self.waitedEnough(); } } // var image=$("<img/>"); image.load(onImageLoadOrError); image.error(onImageLoadOrError); image.prop("src",imageUrl); }); } else{ self.waitedEnough(); } } });

Con este ejemplo, estoy seguro de que encontrarás una buena solución para responder a tu pregunta.

En particular, creo que es posible que desee mover su código lógico "auxiliar" dentro del enlace antes de IronRouter. No dude en hacer preguntas si mi código no está claro.


Podría usar algo sin ironRouter, es decir, en su plantilla. Suponiendo que tiene una plantilla llamada ''carga'' y está usando un diseño llamado ''diseño'' configurado con ironrouter

HTML

<template name="layout"> {{#if isready}} {{yield}} {{else}} {{>loading}} {{/if </template>

Javascript (lado del cliente)

Template.layout.isready = function() { return !Session.get("isnotready"); } Template.edit_Record.helpers({ selectedRecord: function () { Session.set("isnotready", true); wait(3000); var x = myRecords.findOne({_id: this.editid}); Session.set("isnotready, false); return x; } });