为什么我不能将字符串作为数据参数传递给 Blaze.renderWithData()?

Why can't I pass a string as the data argument to Blaze.renderWithData()?

我正在使用以下调用创建 Blaze 视图:

Blaze.renderWithData(Template.my_template, myobj._id, html.node());

my_template 看起来像这样:

<template name="my_template">
  {{> Template.dynamic template=whichTemplate data=sdata}}
</template>

sdata 助手看起来像这样:

sdata: function() {
  return Doodads.findOne({_id: this});
}

失败并出现以下错误:

Exception in template helper: TypeError: selKey.substr is not a function

如果我在该助手中执行 console.log(this),我得到:

String {0: "N", 1: "7", 2: "j", 3: "o", 4: "y", 5: "g", 6: "w", 7: "P", 8: "g", 9: "e", 10: "s", 11: "R", 12: "f", 13: "w", 14: "q", 15: "o", 16: "7", length: 17, [[PrimitiveValue]]: "N7joygwPgesRfwqo7"}

要更正此问题,我可以将 findOne() 行更改为:

  return Doodads.findOne({_id: ""+this});

按预期工作。


我发布这个问题是为了帮助我自己(和其他人)理解这里发生的事情。

我主要想知道:

我已经用 ""+this hack 解决了这个问题,但是有更合适的方法吗?

如果您的数据是从 Meteor 订阅以外的其他来源创建的,则可能是您的 _id 是 MongoDB ObjectId,它不是字符串。

看看 Mongo shell,如果你在 myobj 对象上执行 .findOne,它看起来像

"_id" : ObjectId("57cd946429bca10300f0fd55")

怎么了?

根据Blaze API docs,签名是:

Blaze.renderWithData(templateOrView, data, parentNode, [nextNode], [parentView])

data Object or Function

The data context to use, or a function returning a data context. If a function is provided, it will be reactively re-run.

在您的情况下,数据上下文应该是一个对象,其中包含一个 whichTemplate 属性 和一些您可以在助手中使用的 id

Blaze.renderWithData(Template.my_template, {
  _id: myId, 
  whichTemplate: someTemplateName
}, someNode);

或者,传递一个函数,而不是数据对象,该函数将被反应性地重新运行。

使用此设置,您的帮助程序代码应该类似于:

sdata: function() {
  return Doodads.findOne(this._id);
}

您看到的错误来源

如果您对所遇到错误的原因感兴趣,请查看正在发生的事情:

在 blaze 中,countext 使用 Function.protptype.apply(thisArg, [argsArray])(在 this line 中)绑定到模板助手的 this 引用。

根据EcmaScript标准,如果thisArg是原始类型,它会被装箱。

thisArg

The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.

(source: MDN)

这会导致没有 substr 方法的 String 对象被转移到 MiniMongo.Collectionfind() 方法,fails here.