javascript 等待流星收集完成后再进行下一步
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20942025/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Waiting for meteor collection to finish before next step
提问by Matt H
I have a Meteor template that should be displaying some data.
我有一个应该显示一些数据的 Meteor 模板。
Template.svg_template.rendered = function () {
dataset_collection = Pushups.find({},{fields: { date:1, data:1 }}, {sort: {date: -1}}).fetch();
a = moment(dataset_collection[0].date, "YYYY/M/D");
//more code follows that is also dependent on the collection being completely loaded
};
Sometimes it works, sometimes I get this error:
有时它有效,有时我收到此错误:
Exception from Deps afterFlush function: TypeError: Cannot read property 'date' of undefined
Deps afterFlush 函数的异常:TypeError:无法读取未定义的属性“日期”
I'm not using Deps in any context. As I understand it, the collection is being referenced before it is completely finished loading.
我没有在任何情况下使用 Deps。据我了解,该集合在完全加载完成之前被引用。
I therefore would like to figure out how to simply say "wait until the collection is found before moving on." Should be straightforward, but can't find an updated solution.
因此,我想弄清楚如何简单地说“等到找到集合再继续”。应该很简单,但找不到更新的解决方案。
回答by saimeunt
You are right, you should ensure that code depending on fetching the content of a client-side subscribed collection is executed AFTER the data is properly loaded.
您是对的,您应该确保在正确加载数据后执行取决于获取客户端订阅集合的内容的代码。
You can achieve this using a new pattern introduced in Meteor 1.0.4 : https://docs.meteor.com/#/full/Blaze-TemplateInstance-subscribe
您可以使用 Meteor 1.0.4 中引入的新模式实现此目的:https: //docs.meteor.com/#/full/Blaze-TemplateInstance-subscribe
client/views/svg/svg.js
client/views/svg/svg.js
Template.outer.onCreated(function(){
// subscribe to the publication responsible for sending the Pushups
// documents down to the client
this.subscribe("pushupsPub");
});
client/views/svg/svg.html
client/views/svg/svg.html
<template name="outer">
{{#if Template.subscriptionsReady}}
{{> svgTemplate}}
{{else}}
Loading...
{{/if}}
</template>
In the Spacebars template declaration, we use an encapsulating outer
template to handle the template level subscription pattern.
We subscribe to the publication in the onCreated
lifecycle event, and we use the special reactive helper Template.subscriptionsReady
to only render the svgTemplate
once the subscription is ready (data is available in the browser).
At this point, we can safely query the Pushups
collection in the svgTemplate
onRendered
lifecycle event because we made sure data made its way to the client :
在 Spacebars 模板声明中,我们使用封装outer
模板来处理模板级订阅模式。我们在onCreated
生命周期事件中订阅发布,并且我们使用特殊的反应式助手Template.subscriptionsReady
仅svgTemplate
在订阅准备好后才呈现(数据在浏览器中可用)。此时,我们可以安全地Pushups
在svgTemplate
onRendered
生命周期事件中查询集合,因为我们确保数据已到达客户端:
Template.svgTemplate.onRendered(function(){
console.log(Pushups.find().fetch());
});
Alternatively, you could use the iron:router
(https://github.com/iron-meteor/iron-router), which provides another design pattern to achieve this common Meteor related issue, moving subscription handling at the route level instead of template level.
或者,您可以使用iron:router
( https://github.com/iron-meteor/iron-router),它提供了另一种设计模式来解决这个常见的 Meteor 相关问题,在路由级别而不是模板级别移动订阅处理。
Add the package to your project :
将包添加到您的项目中:
meteor add iron:router
lib/router.js
lib/router.js
Router.route("/svg", {
name: "svg",
template: "svgTemplate",
waitOn: function(){
// waitOn makes sure that this publication is ready before rendering your template
return Meteor.subscribe("publication");
},
data: function(){
// this will be used as the current data context in your template
return Pushups.find(/*...*/);
}
});
Using this simple piece of code you'll get what you want plus a lot of added functionalities. You can have a look at the Iron Router guide which explains in great details these features.
使用这段简单的代码,您将获得所需的内容以及许多附加功能。您可以查看 Iron Router 指南,其中详细介绍了这些功能。
https://github.com/iron-meteor/iron-router/blob/devel/Guide.md
https://github.com/iron-meteor/iron-router/blob/devel/Guide.md
EDIT 18/3/2015 : reworked the answer because it contained outdated material and still received upvotes nonetheless.
编辑 18/3/2015:重新设计答案,因为它包含过时的材料,但仍然收到了赞成票。
回答by David Weldon
This is one of those problems that I really wish the basic meteor documentation addressed directly. It's confusing because:
这是我真正希望基本流星文档直接解决的问题之一。这令人困惑,因为:
- You did the correct thing according to the API.
- You get errors for
Deps
which doesn't point you to the root issue.
- 您根据 API 做了正确的事情。
- 您收到的错误
Deps
并未将您指向根本问题。
So as you have already figured out, your data isn't ready when the template gets rendered. What's the easiest solution? Assume that the data may not be ready. The examplesdo a lot of this. From leaderboard.js:
因此,正如您已经发现的那样,当模板呈现时,您的数据还没有准备好。什么是最简单的解决方案?假设数据可能没有准备好。这些例子做了很多这样的事情。从排行榜.js:
Template.leaderboard.selected_name = function () {
var player = Players.findOne(Session.get("selected_player"));
return player && player.name;
};
Only if player
is actually found, will player.name
be accessed. In coffeescript you can use soaks to accomplish the same thing.
只有player
真正找到了,才会player.name
被访问。在 coffeescript 中,你可以使用浸泡来完成同样的事情。
saimeunt's suggestion of iron-router's waitOn
is good for this particular use case, but be aware you are very likely to run into situations in your app where the data just doesn't exist in the database, or the property you want doesn't exist on the fetched object.
的saimeunt的建议铁路由器的waitOn
是这个特定用例好,但要知道,你很可能在数据只是在数据库中不存在,或者你想要的属性不会碰到你的应用情况存在于获取的对象上。
The unfortunate reality is that a bit of defensive programming is necessary in many of these cases.
不幸的现实是,在许多情况下需要一些防御性编程。
回答by capnbishop
Using iron-router to wait on the subscription works, but I like to keep subscriptions centrally managed in something like a collections.js file. Instead, I take advantage of Meteor's file load orderto have subscriptions loaded before everything else.
使用 Iron-router 等待订阅有效,但我喜欢在 collections.js 文件中集中管理订阅。相反,我利用 Meteor 的文件加载顺序在其他所有内容之前加载订阅。
Here's what my collections.js file might look like:
我的 collections.js 文件可能如下所示:
// ****************************** Collections **********************************
Groups = new Mongo.Collection("groups");
// ****************************** Methods **************************************
myGroups = function (userId) {
return Groups.find({"members":{$elemMatch:{"user_id":userId}}});
};
// ****************************** Subscriptions ********************************
if(Meteor.isClient){
Meteor.subscribe("groups");
}
// ****************************** Publications *********************************
if(Meteor.isServer){
Meteor.publish("groups", function () {
return myGroups(this.userId);
});
}
I then put collections.js into a lib/
folder so that it will get loaded prior to my typical client code. That way the subscription is centralized to a single collections.js file, and not as part of my routes. This example also centralizes my queries, so client code can use the same method to pull data:
然后我将 collections.js 放入一个lib/
文件夹中,以便在我的典型客户端代码之前加载它。这样订阅就集中在一个 collections.js 文件中,而不是作为我的路由的一部分。这个例子也集中了我的查询,所以客户端代码可以使用相同的方法来拉取数据:
var groups = myGroups(Meteor.userId());