编辑: 我已经更新了下面的代码,因为它很脆弱,并且为了将其放入上下文中,使其更容易测试。我还添加了一个警告 - 在大多数情况下,您将希望使用@zorlak或@englandpost的方法(请参见下文)。
首先,向 @zorlak 致敬,他挖掘出了我的旧问题,而没有人回答。我已经通过从 @David Wihl 那里获得的一些
见解 解决了这个问题,并将发布自己的解决方案。在其他人有机会发表意见之前,我将暂停选择正确的答案。
@zorlak 的答案解决了单个字段的自动完成问题,但正如问题所述,我正在寻找一个可以反应更新的
数组,自动完成只是其中之一的示例。拥有此数组的优点是它可以在任何地方使用(不仅限于模板助手),并且可以在代码中多次使用而无需重新执行查询(以及减少查询为数组的
_.pluck()
)。在我的情况下,这个数组最终会出现在多个自动完成字段以及验证和其他地方。我提出的优点可能在大多数 Meteor 应用程序中并不显著(请留言),但对我来说似乎是一个优点。
为了使数组具有响应性,只需在
Meteor.autorun()
回调函数内构建它 - 它将在目标集合更改时重新执行(但仅在此时,避免重复查询)。这是我正在寻找的关键洞见。此外,使用
Template.rendered()
回调比我在问题中使用的
set_typeahead
模板助手更加干净和不容易出错。下面的代码使用
underscore.js的_.pluck()
从集合中提取数组,并使用
Twitter bootstrap's $.typeahead()
创建自动完成。
更新的代码:我已经编辑了代码,这样你就可以在一个股票
meteor create
的测试环境中尝试。你的 html 需要在 'hello' 模板中添加一行
<input id="typeahead" />
。
@Items
带有
@
符号,以使
Items
在控制台上作为全局变量可用(
Meteor 0.6.0 添加了文件级别变量作用域)。这样,您可以在控制台中输入新项目,例如
Items.insert({name: "joe"})
,但是
@
对于代码工作并不必要。独立使用的另一个必要更改是 typeahead 函数现在将源设置为函数 (
->
),因此当激活时它将查询
items
而不是在渲染时被设置,这允许它利用对
items
的更改。
@Items = new Meteor.Collection("items")
items = {}
if Meteor.isClient
Meteor.startup ->
Meteor.autorun ->
items = _(Items.find().fetch()).pluck "name"
console.log items
Template.hello.rendered = ->
$('#typeahead').typeahead {source: -> _(Items.find().fetch()).pluck "name"}
注意!我们创建的数组本身不是一个响应式数据源。 typeahead source:
需要设置为返回 items
的 函数 ->
,原因是当 Meteor 开始运行时,代码会在 Minimongo 从服务器获取数据之前运行,而 items
设置为空数组。然后 Minimongo 接收到数据,items
被更新。如果您打开控制台运行上面的代码,您可以看到这个过程:console.log items
如果有任何存储的数据,将会记录两次。
Template.x.rendered()
的调用不会设置响应式上下文,因此不会由于响应式元素的更改而重新触发(要检查这一点,请在调试器中暂停代码并检查Deps.currentComputation
- 如果它为null
,则您不处于响应式上下文中,对响应式元素的更改将被忽略)。但您可能会惊讶地发现,您的模板和助手也不会对items
的更改做出反应 - 使用#each
迭代items
的模板将呈现为空,并且永远不会重新渲染。您可以使其作为响应式源(最简单的方法是使用Session.set()
存储结果,或者 您可以自己完成),但除非您正在进行非常昂贵的计算,应尽可能少地运行,否则最好使用@zorlak或@englandpost的方法。虽然让应用程序重复查询数据库似乎很昂贵,但Minimongo会在本地缓存数据,避免网络,因此速度相当快。因此,在大多数情况下,最好只使用
Template.hello.rendered = ->
$('#typeahead').typeahead {source: -> _(Items.find().fetch()).pluck "name"}
除非你发现你的应用程序真的变得很慢。