我想知道是否有人构建了自己的waitOn函数?我不是使用预订来驱动waitOn,而是想等待一个助手来触发就绪状态,如下所示:
I was wondering whether anyone has built their own waitOn function? I am not using subscribe to drive the waitOn but rather I want to wait on a helper to trigger the ready state, something like this:
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; } });推荐答案
我设计了自己的模式以与自定义的waitOn一起使用. 您应该意识到,IronRouter不会呈现您的模板(因此,除非您手动调用它们,否则通常不会提供其帮助器),除非waitOn函数中指定的每个句柄都已准备就绪.
I've designed my own pattern to work with a custom waitOn. You should be aware that IronRouter won't render your template (and thus none of its helpers except if you call them manually which is usually odd) UNLESS every handles specified in the waitOn function are ready.
waitOn是一个反应式计算,因此您指定的句柄应该是反应性数据源,并且随着它们的就绪状态的发展,waitOn将自动重新评估,最终将通知IronRouter可以渲染模板.
waitOn is a reactive computation, so the handles you specify should be reactive data sources, and as their ready state evolves, waitOn will be reevaluated automatically and ultimately it will notify the IronRouter that it's OK to render the template.
因此,如果我们想将waitOn与订阅句柄以外的其他功能一起使用,则必须使用反应性ready()方法(这来自文档)来实现我们自己的对象. 我们将这个对象称为侍者",因为它的作用是等待事件发生,然后将其内部状态设置为就绪.
So if we want to use waitOn with something else than subscription handles, we have to implement our own object with a reactive ready() method (this is from the docs). We'll call this object a "Waiter" because its role is to wait until some event happens and then it sets his internal state to ready.
我将向您介绍一个简单的示例,该示例解决了一个常见问题:图像预加载. 假设您有一个模板,用于渲染其src属性存储在Collection中的图像元素:您只想在客户端加载图像时才渲染该模板.
I'll introduce you a simple example which solves a common problem : image preloading. Suppose you have a template rendering image elements whose src attributes are stored in a Collection : you'd like to render the template only when the images are loaded client-side.
<template name="view"> <div> <h1>{{title}}</h1> <img src="{{firstImageUrl}}" /> <img src="{{secondImageUrl}}" /> </div> </template>我想出了以下界面:
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); } });使用此路由定义,由于在ImagePreloadingWaiter接口句柄上等待的waitOn方法,我们将显示加载模板,直到最终加载存储在集合中的图像URL.
Using this route definition, we display the loading template until the images URLs stored in our collection are finally loaded, thanks to the waitOn method which waits on our ImagePreloadingWaiter interface handle.
好吧,现在我们已经有了想要使用的接口的概述,让我们实际实现它:
Ok so now that we have an overview of the interface we'd like to use, let's actually implement it :
// 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(); } } });使用此示例,我确定您会找到一个很好的解决方案来回答您的问题.
Using this example I'm sure you will figure out a nice solution to answer your question.
尤其是,我认为您可能希望将Ironhelpr钩子之前的帮助程序"逻辑代码移入其中. 如果我的代码不清楚,请随时提出问题.
In particular, I think you may want to move your "helper" logic code inside the before IronRouter hook. Don't hesitate to ask questions if my code is unclear.
更多推荐
带有自定义waitOn的流星铁路由器
发布评论