【问题标题】:Waiting for meteor collection to finish before next step在下一步之前等待流星收集完成
【发布时间】:2015-07-24 01:57:20
【问题描述】:

我有一个应该显示一些数据的 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
};

有时它有效,有时我收到此错误:

Deps afterFlush 函数的异常:TypeError: Cannot read property 'date' of undefined

我没有在任何情况下使用 Deps。据我了解,该集合在完全加载完成之前就被引用了。

因此,我想弄清楚如何简单地说“等到找到集合后再继续”。应该很简单,但找不到更新的解决方案。

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

    您是对的,您应该确保在正确加载数据后执行依赖于获取客户端订阅集合内容的代码。

    您可以使用 Meteor 1.0.4 中引入的新模式来实现这一点:https://docs.meteor.com/#/full/Blaze-TemplateInstance-subscribe

    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

    <template name="outer">
      {{#if Template.subscriptionsReady}}
        {{> svgTemplate}}
      {{else}}
        Loading...
      {{/if}}
    </template>
    

    在空格键模板声明中,我们使用封装outer 模板来处理模板级订阅模式。 我们在 onCreated 生命周期事件中订阅发布,并且我们使用特殊的响应式帮助器 Template.subscriptionsReady 仅在订阅准备好后才呈现 svgTemplate(数据在浏览器中可用)。 此时,我们可以在 svgTemplate onRendered 生命周期事件中安全地查询 Pushups 集合,因为我们确保数据能够到达客户端:

    Template.svgTemplate.onRendered(function(){
      console.log(Pushups.find().fetch());
    });
    

    或者,您可以使用iron:router (https://github.com/iron-meteor/iron-router),它提供了另一种设计模式来解决这个常见的 Meteor 相关问题,将订阅处理移动到路由级别而不是模板级别。

    将包添加到您的项目中:

    meteor add iron:router
    

    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(/*...*/);
      }
    });
    

    使用这段简单的代码,您将获得所需的内容以及许多附加功能。 您可以查看 Iron Router 指南,其中详细解释了这些功能。

    https://github.com/iron-meteor/iron-router/blob/devel/Guide.md

    编辑 2015 年 3 月 18 日:修改了答案,因为它包含过时的材料,但仍然收到了赞成票。

    【讨论】:

    • 感谢您修改您的答案。流星移动很快,有很多过时的信息。
    • 再次修改答案以鼓励使用模板级订阅,这是一种进入最新版本 Meteor 的设计模式。
    • 应该是公认的答案。感谢 Iron:router 和您的回答,我已经能够轻松解决我的问题。谢了哥们! :-)
    【解决方案2】:

    这是我真正希望基本流星文档直接解决的问题之一。这很令人困惑,因为:

    1. 您根据 API 做了正确的事情。
    2. Deps 出现错误,这并没有指出问题的根源。

    所以您已经知道,当模板被渲染时,您的数据还没有准备好。最简单的解决方案是什么?假设数据可能还没有准备好。 examples 做了很多这样的事情。来自leaderboard.js

    Template.leaderboard.selected_name = function () {
        var player = Players.findOne(Session.get("selected_player"));
        return player && player.name;
    };
    

    只有当player被实际找到时,player.name才会被访问。在咖啡脚本中,您可以使用浸泡来完成同样的事情。

    saimeunt 对iron-routerwaitOn 的建议非常适合这种特殊用例,但请注意,您很可能会在应用程序中遇到数据库中不存在数据的情况,或者获取的对象上不存在您想要的属性。

    不幸的现实是,在许多情况下,一些防御性编程是必要的。

    【讨论】:

      【解决方案3】:

      使用 iron-router 等待订阅工作,但我喜欢将订阅集中管理在一个类似 collections.js 文件中。相反,我利用 Meteor 的 file load order 来先加载订阅。

      我的 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);
        });
      }
      

      然后我将 collections.js 放入 lib/ 文件夹中,以便在我的典型客户端代码之前加载它。这样订阅就集中在一个 collections.js 文件中,而不是我的路由的一部分。这个例子也集中了我的查询,所以客户端代码可以使用相同的方法来拉取数据:

      var groups = myGroups(Meteor.userId());
      

      【讨论】:

        猜你喜欢
        • 2020-05-25
        • 1970-01-01
        • 1970-01-01
        • 2019-12-31
        • 2014-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-02
        相关资源
        最近更新 更多