UI helper 函数在 Meteor 中没有订阅数据

Posted

技术标签:

【中文标题】UI helper 函数在 Meteor 中没有订阅数据【英文标题】:UI helper function does not have the subscription data in Meteor 【发布时间】:2015-10-22 16:23:33 【问题描述】:

我对 Meteor 还很陌生。

我有一个模板辅助函数,它需要处理我从服务器端发布的数据。当页面加载时,下面配置文件的值为undefined。但在那之后,当我从浏览器的控制台执行相同的代码 sn-p 时,它工作得很好。据我了解,模板助手是在数据发布之前执行的。如何等到数据发布后再运行 UI 助手?

这里是相关代码。


辅助功能

Template.header.helpers(  
  me: function() 
    var user = Meteor.users.findOne(Meteor.userId());
    if (user) 
      return Profiles.findOne(
        spid: user.profile.spid
     );
    

    return null;
  
);

HTML 模板

<template name="header">
  <header class="ui fixed inverted menu">
    > thumb user=me
  </header>
</template>

缩略图模板

<template name="thumb">
  #with user
  <div class="thumb">
    <div class="text" style="background-color:color">
      initials name
    </div>
    <div class="pic" style="background-image:url('pic')"></div>
  </div>
  /with
</template>

出版物

Meteor.publish('profiles', function() 
  return Profiles.all();
);

Meteor.publish('departments', function() 
  return Departments.all();
);

Meteor.publish('requestServiceIds', function() 
  return Requests.getServiceIds();
);

Meteor.publish('relevantServices', function() 
  return Services.getRelevant(this.userId, 5);
);

路由器

Router.configure(
  layoutTemplate: 'main',
  waitOn: function() 
    Deps.autorun(function() 
      Meteor.subscribe('profiles', Partitioner.group());
      Meteor.subscribe('departments', Partitioner.group());
    );
  
);

Router.onBeforeAction(function() 
  if (this.route.getName() === 'not-authorized') return this.next();

  if (!Meteor.userId() || !Cookie.get('TKN')) 
    this.render('login');
   else 
    this.next();
  
);

Router.route('/', 
  name: 'home',
  waitOn: function() 
    Deps.autorun(function() 
      Meteor.subscribe('requestServiceIds', Partitioner.group());
      Meteor.subscribe('relevantServices', Partitioner.group());
    );
  
);

---

更新 1

我稍微更新了路由器。但这似乎没有任何影响。

Router.configure(
  layoutTemplate: 'main',
  waitOn: function() 
    // Deps.autorun(function() 
    //   Meteor.subscribe('profiles', Partitioner.group());
    //   Meteor.subscribe('departments', Partitioner.group());
    // );

    return [
      Meteor.subscribe('profiles', Partitioner.group()),
      Meteor.subscribe('departments', Partitioner.group())
    ];
  
);

Router.route('/', 
  name: 'home',
  waitOn: function() 
    // Deps.autorun(function() 
    //   Meteor.subscribe('requestServiceIds', Partitioner.group());
    //   Meteor.subscribe('relevantServices', Partitioner.group());
    // );

    return [
      Meteor.subscribe('requestServiceIds', Partitioner.group()),
      Meteor.subscribe('relevantServices', Partitioner.group())
    ];
  
);

【问题讨论】:

为什么在waitOn 函数中使用Deps.autorun?你能试试waitOn: function () return [Meteor.subscribe('profiles', Partitioner.group()), Meteor.subscribe('departments', Partitioner.group())]; waitOn: function () return [Meteor.subscribe('requestServiceIds', Partitioner.group()), Meteor.subscribe('relevantServices', Partitioner.group())]; 吗? @MatthiasEckhart:我使用的是Deps,因为我使用的是Partitioner 包,这是atmospherejs.com/mizzao/partitioner 推荐的 @MatthiasEckhart:我只是按照建议尝试过,似乎没有任何区别 好吧,waitOn 应该在订阅准备好之前阻止模板呈现。也许您可以使用guard expression 来解决您的问题。 【参考方案1】:

创建一个像这样的哑加载模板(使用字体真棒):

<template name="loading">
    <div class="loading">
        <i class="fa fa-circle-o-notch fa-4x fa-spin"></i>
    </div>
</template>

并尝试将您的 Router.configure() 部分替换为以下内容:

Router.configure(
  layoutTemplate: 'main',
  action: function() 
        if(this.isReady())  this.render();  else this.render("loading");
    ,
    isReady: function() 
        var subs = [
            Meteor.subscribe('profiles', Partitioner.group());
            Meteor.subscribe('departments', Partitioner.group());
        ];
        var ready = true;
        _.each(subs, function(sub) 
            if(!sub.ready())
            ready = false;
        );
        return ready;
    ,

    data: function() 
        return 
            params: this.params || ,
            profiles: Profiles.find(),
            departments: Departments.find()
        ;
    
  
);

我想这可以使用waitOn 来实现,但由于你的方法行不通,我给你一个我每天都用的有效食谱。代码灵感来自meteor Kitchen 生成的代码。


回答你的cmets:

关于Action没有被触发,可能是因为我们试图放入Router.configure里面。我不这样做,这里有一些关于我如何实现它的细节。

首先,我在 router.js 文件中为每个路由设置了一个控制器(我也有 Router.configure() 函数。看起来像这样:

Router.map(function () 
    this.route("login", path: "/login", controller: "LoginController");
    // other routes

接下来,我创建一个控制器,将其存储在与客户端视图模板相同的文件夹中。看起来是这样的:

this.LoginController = RouteController.extend(
    template: "Login",


    yieldTemplates: 
        /*YIELD_TEMPLATES*/
    ,

    onBeforeAction: function() 
        /*BEFORE_FUNCTION*/
        this.next();
    ,

    action: function() 
        if(this.isReady())  this.render();  else  this.render("loading"); 
        /*ACTION_FUNCTION*/
    ,

    isReady: function() 


        var subs = [
        ];
        var ready = true;
        _.each(subs, function(sub) 
            if(!sub.ready())
                ready = false;
        );
        return ready;
    ,

    data: function() 


        return 
            params: this.params || 
        ;
        /*DATA_FUNCTION*/
    ,

    onAfterAction: function() 
    
);

所以当我使用控制器扩展路由时,这个action 函数正在工作。也许它会解决你的问题。

为了完整起见,这是我的Router.configure() 的样子:

Router.configure(
  templateNameConverter: "upperCamelCase",
  routeControllerNameConverter: "upperCamelCase",
  layoutTemplate: "layout",
  notFoundTemplate: "notFound",
  loadingTemplate: "loading",
 //I removed the rest because it is useless.
);

【讨论】:

试过了。不工作。有了这个部门也停止了工作。 好吧,action 函数没有被调用。我在动作函数中添加了console.log('test'),但没有得到任何输出。

以上是关于UI helper 函数在 Meteor 中没有订阅数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Meteor 中保存用户位置

Meteor Account UI Bootstrap 登录回调

当我们从 Mongo 控制台更新集合时,Meteor Apollo 没有更新 UI

如何在模板助手中使用 Meteor 方法

Meteor 是不是支持嵌套助手(子表达式)?

Meteor.call 会影响乐观 UI 吗?