Meteor模板渲染 - 为什么集合为空?

6
在下面的基本示例中,为什么渲染函数中返回的集合为空?
Autopublish已启用。页面加载后,在javascript控制台中调用命令Coll.find().fetch()会返回正确的条目集。
以下是代码:

t.js
Coll = new  Meteor.Collection("coll");

if (Meteor.isClient) {
  Template.tpl.rendered = function(){
    console.log(Coll.find().fetch()); // <-- This line prints empty array
  };
}

if (Meteor.isServer) {
  Meteor.startup(function () {
      if (Coll.find().count() === 0) {
          var f = ["foo","bar"];
          for (var i = 0; i < f.length; i++)
              Coll.insert({f: f[i]});
      }
  });
}

以及 t.html 文件

<head>
  <title>test</title>
</head>

<body>
  {{> tpl}}
</body>

<template name="tpl">
  Test tpl
</template>

这是因为你的集合尚未加载。Template.rendered被触发,并不意味着你的集合已经加载完成。请查看线程。 - sohel khalifa
1个回答

5
Meteor是基于数据传输的结构构建的。这意味着当应用程序最初加载时,先发送HTML和JS,然后再发送数据。
您必须使用反应性来检查数据更改或检查集合订阅何时完成(这需要删除autopublish包)。 (您可以在文档中查看如何将应用程序移动到手动订阅:http://docs.meteor.com/#publishandsubscribe
订阅回调会告诉您何时返回数据:
Meteor.subscribe("coll", function() {
    //Data subscription complete. All data is downloaded
});

一个模板也可以变成响应式的(就像你现在正在做的),但是 .rendered 没有被调用,因为 Meteor 首先会检查模板的 HTML 是否已更改,只有当它不同才会更改其 HTML 并调用渲染回调函数。
你在这里的选项是 1)使用 Deps.autorun,或者
2)我不确定为什么你在渲染回调中使用它,但如果必须放在那里,你需要确保模板的 HTML 发生了变化,通过从你的集合中引入一些东西来使其在新数据引入时发生变化。

我也卡在这里了。你能详细说明一下吗?我正在尝试手动渲染一个生成c3 js图表的模板,并尝试从数据库加载数据,但是像上面一样得到了空数组。 - radtek
@radtek Meteor的工作方式是先发送HTML,然后再发送数据。当您的渲染回调触发时,数据可能已经被发送或者还未被发送。在绘制图表之前,您必须使用上述方法之一或iron router的subscribe('..').wait()命令确保等待数据到达。 - Tarang
是的,我知道这些。我想要的是一个使用c3 js meteor包的示例。使用静态数据可以正常工作,但应该有一个最佳实践示例来处理数据库数据。我晚些时候会看看我能找到什么。当我尝试呈现HTML、然后订阅并通过handlebars输出数据时,我尝试在模板本身中生成JS脚本,但是当我进行循环时,handlebars会创建一个新行,因此它甚至无法解析JS。var data = []; data.push({{each_item}});。所以我认为这种方法太过于hacky,需要有更好的方法。 - radtek
谢谢!我目前已经将订阅放在了 client.js 文件的顶部(我正在使用 /client/server 目录结构)。我会试一试。 - radtek
我使用了Meteor.subscribe("col").ready回调函数,似乎解决了问题。我转换到highcharts,因为它有更好的文档,但在数据刷新时,图表尚未重新绘制,尽管调用了设置所有内容的代码(helper)。所以必须找到一种方法来销毁旧的并重新绘制新的...离题了。 - radtek
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接