我想知道是否有人建立了自己的waitOn功能?我没有使用subscribe来驱动waitOn,而是我想等待帮助器来触发就绪状态,如下所示:
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;
}
});
答案 0 :(得分:2)
我设计了自己的模式来处理自定义waitOn。 您应该知道IronRouter不会渲染您的模板(因此除非您手动调用它们,否则它们都没有帮助,这通常很奇怪),除非waitOn函数中指定的每个句柄都准备就绪。
waitOn是一个被动计算,所以你指定的句柄应该是被动数据源,随着它们的就绪状态的发展,waitOn将被自动重新评估,最终它会通知IronRouter可以呈现模板。
因此,如果我们想使用waitOn而不是订阅句柄,我们必须使用被动的ready()方法实现我们自己的对象(这来自文档)。 我们将此对象称为“服务员”,因为它的作用是等到某个事件发生,然后将其内部状态设置为准备好。
我将向您介绍一个解决常见问题的简单示例:图像预加载。 假设您有一个模板渲染图像元素,其src属性存储在Collection中:您只想在客户端加载图像时才渲染模板。
<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);
}
});
使用此路由定义,我们显示加载模板,直到最终加载存储在我们集合中的图像URL,这要归功于等待我们的ImagePreloadingWaiter接口句柄的waitOn方法。
好的,现在我们已经对我们想要使用的界面进行了概述,让我们实际实现它:
// 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();
}
}
});
使用这个例子我相信你会找到一个很好的解决方案来回答你的问题。
特别是,我认为您可能希望将您的“帮助”逻辑代码移到IronRouter挂钩之前。 如果我的代码不清楚,请不要犹豫提问。
答案 1 :(得分:1)
您可以在模板中使用没有ironRouter的东西。假设你有一个名为'loading'的模板,并且你正在使用一个名为'layout'的布局设置为ironrouter
HTML
<template name="layout">
{{#if isready}}
{{yield}}
{{else}}
{{>loading}}
{{/if
</template>
Javascript(客户端)
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;
}
});