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

Posted

技术标签:

【中文标题】如何在模板助手中使用 Meteor 方法【英文标题】:How to use Meteor methods inside of a template helper 【发布时间】:2014-04-04 13:30:54 【问题描述】:

如何定义一个也可以在模板助手中调用的 Meteor 方法?

我有这两个文件:

文件:lib/test.js

Meteor.methods(
    viewTest : function (str) 
        return str;
    
);

文件:client/myView.js

Template.helloWorld.helpers(
    txt : function () 
        var str = Meteor.call('viewTest', 'Hello World.');
        return str;
    
);

当我给“str”一个正常的字符串时,一切正常。但在这种情况下,我的模板没有任何价值。我在同一个文件中为测试定义了该方法是普通函数并尝试调用该函数的文件。我得到的错误是该功能不存在。所以我认为 Meteor 在知道我为它定义的方法之前会尝试渲染模板。但我认为这有点不寻常——不是吗?

【问题讨论】:

【参考方案1】:

现在有一种新方法可以做到这一点(Meteor 0.9.3.1),它不会污染 Session 命名空间

Template.helloWorld.helpers(
    txt: function () 
        return Template.instance().myAsyncValue.get();
    
);

Template.helloWorld.created = function ()
    var self = this;
    self.myAsyncValue = new ReactiveVar("Waiting for response from server...");
    Meteor.call('getAsyncValue', function (err, asyncValue) 
        if (err)
            console.log(err);
        else 
            self.myAsyncValue.set(asyncValue);
    );

在“created”回调中,您创建一个 ReactiveVariable 的新实例(请参阅docs)并将其附加到模板实例。

然后您调用您的方法,当回调触发时,您将返回的值附加到反应变量。

然后你可以设置你的助手返回响应变量的值(现在附加到模板实例),当方法返回时它会重新运行。

但请注意,您必须添加 reactive-var 包才能使其工作

$ meteor add reactive-var

【讨论】:

这仍然是首选方法吗? 这不是非反应性的吗?由于ReactiveVar 仅在created 处理程序中更新?因此,如果 asyncValue 得到更新,它不会更新您的模板,除非它刷新...? @evolross 操作没有要求响应式,只是方法调用的结果会更新模板。 真的...仅供参考,以防人们认为它会自动响应,因为它使用了模板助手(可能是 Meteor 的新手)。 很好,但是如果我要返回一个对象对象,我现在该如何迭代呢? #each 作品仅接受数组。我希望能够访问通过调用返回的每个对象的属性。【参考方案2】:

Sashko 添加了一个名为meteor-reactive-method 的简洁小包来解决这个问题。

$ meteor add simple:reactive-method
Template.helloWorld.helpers(
  txt: function() 
    return ReactiveMethod.call('viewTest', 'Hello World.');
  
);

正如我在common mistakes 中指出的,助手应该没有副作用,所以我会谨慎使用这种技术。但是,对于以下情况,这是一个非常方便的捷径:

助手应该只触发一次(它不依赖于反应状态)。 调用的方法不会改变数据库。

【讨论】:

【参考方案3】:

由于请求是异步的,因此您需要将返回值与 Session 变量接口:

Template.helloWorld.helpers(
    txt : function () 
        return Session.get("txt") || "Loading";
    
);

Template.helloWorld.created = function() 
    Meteor.call('viewTest', 'Hello World.', function(err, result) 
        Session.set("txt", result);
    );


所以 .rendered 应该在你的模板加载时被调用一次(至少它应该使用新版本的 Meteor。)

将调用并显示该值。否则它会说“正在加载”。

【讨论】:

这解决了问题。但在我的特殊情况下,这不是一个好的解决方案,因为我必须在模板渲染之前获得 tge 正确的返回值。在我的特殊情况下,我现在使用典型的 javascript 函数来解决它。你得到了“正确答案”的标记,因为它会解决它——它是否解决了我的特殊情况并不重要。谢谢 @TimoRütten 您是否考虑过不使用 Meteor.call 而是使用带有本地集合的转换? 本地收藏?在我的情况下,集合的使用无关紧要。问题是我必须在模板被渲染之前得到一个返回值。也许我不明白你的问题?【参考方案4】:

客户端的方法是异步的,它们的返回值总是未定义的。要获取方法返回的实际值,需要提供回调:

Meteor.call('method', 'argument', function(error, result) 
    ....
);

现在,没有简单的方法可以在帮助程序中使用结果。但是,您可以将其作为数据对象存储在模板中,然后在帮助程序中返回:

Template.template.created = function() 
    var self = this;
    self.data.elephantDep = new Deps.Dependency();
    self.data.elephant = '';
    Meteor.call('getElephant', 'greenOne', function(error, result) 
        self.data.elephant = result;
        self.data.elephantDep.changed();
    );
;

Template.template.showElephant = function() 
    this.elephantDep.depend();
    return this.elephant;
;

【讨论】:

或者,您可以按照 Akshat 的建议使用 Session 变量,而不必担心依赖关系。然而,这种方法的优点是它是模板本地的。 感谢 Hubert,我一直在寻找提供模板特定依赖项的东西。那么如果模板被更改/加载回来,依赖关系是否也会被清除? 是的,这对我来说适用于特定于模板的依赖项。我做了类似的事情,但也用破坏清除了它们【参考方案5】:

这是预期的行为。您没有按预期使用methods

您的代码定义了一个服务器方法viewTest 和客户端上具有相同名称的相应方法存根。

Meteor.call('viewTest', 'Hello World.'); 远程调用服务器上的viewTest 并在客户端上并行运行存根。

关于stub的返回值请看文档here,特别是:

在客户端,存根的返回值被忽略。存根运行 因为它们的副作用:它们旨在模拟 服务器的方法将做什么,但无需等待回合 行程延误。

关于服务端方法的返回值请看文档here,特别是:

在客户端,如果你不传递回调并且你不在一个 存根,调用将返回未定义,您将无法获取 方法的返回值。那是因为客户端没有 光纤,所以实际上没有任何方法可以阻止遥控器 方法的执行。

【讨论】:

【参考方案6】:

@msavin 有一个很好的小包:https://atmospherejs.com/msavin/fetcher

【讨论】:

以上是关于如何在模板助手中使用 Meteor 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Meteor 中将全局模板助手放在一起?

如何从 Meteor 模板助手返回模板?

如何从 Meteor 模板将多个参数传递给空格键助手?

Meteor:从另一个助手访问模板助手(或变量)

我应该在路由逻辑或 Meteor 模板助手中提供数据吗?

在模板上下文中从另一个助手调用一个助手 (Meteor 0.9.4)