非反应性助手和模板#each崩溃

时间:2017-04-21 17:31:30

标签: mongodb templates variables meteor-blaze reactive

这是一个包含动态查询的帮助程序的问题,该动态查询涉及反应变量和在更改反应变量值时不重新运行的$ where运算符。然后关于如何尝试解决它会导致奇怪的系统行为和崩溃。

我有一个模板,我们要在其中显示在#each循环中插入的已找到文档的列表:

<template name="todo">
    {{#each pendingMTs}}
        <button class="showPendMT">
            <h4> - <strong> {{name}}</strong> </h4>
        </button>
    {{/each}}
</template>

pendingMTs帮助器使用动态和某种精心设计的简化查询来搜索Tasks集合中的文档,这些查询涉及使用$ where运算符:

pendingMTs() {
    return Tasks.find( 
        { $and: [ { owner: Meteor.userId() },  
                  { time: { $gt: 0 } },     
                  { $where: function() 
{ return moment(this.createdAt).add( (((this.timeuts == 'Days') ? 1 : ((this.timeuts=='Meses') ? 30 : 365)) * this.time), 'days').diff(moment([currYear.get(), currMonth.get()])) < 0; }} 
                ] 
        }); 
}

搜索中涉及的两个反应变量是在创建模板时定义的:

Template.todo.onCreated(function() {
    var year = moment().format("YYYY");
    var month = moment().format("M"); 
    month = month - 1; //to values from 0 to 11

    currYear = new ReactiveVar(year);   
    currMonth = new ReactiveVar(month);
});

然后在事件处理程序中,我们在'select'更改时修改反应变量,例如currMonth:

'change #monthForecast' (event) {
    event.preventDefault();
    const target = event.target;
    currMonth.set( target.value );
},

第一个问题是,尽管我们通过事件处理程序修改了反应变量的值,但是不会重新运行帮助程序:为什么?

认为这可能是由于反应变量在$ where函数内部的事实,我在帮助器的开头添加了一个简单的行,以便在帮助器中为它们创建意识:

var rerun = currYear.get(); rerun = currMonth.get(); 

现在肯定的是,任何时候任何2个反应变量都被改变了,帮助者重新运行。但不幸的是,这导致了一种非常奇怪的行为:

  • 如果修改了反应变量,但没有影响帮助程序检索到的文档,系统运行正常,但是:
  • 当修改后的反应变量导致帮助程序检索的文档多于第一次检索的文档数量时,系统崩溃(因此新文档未显示在#each模板中):

    Exception from Tracker recompute function:  meteor.js:930:11
    Error: Bad index in range.getMember: 3
    

在查找原因时,我发现给出的错误索引号(在本例中为3)始终等于第一次执行帮助程序时检索的文档数。在这种情况下,在修改其中一个反应变量的值之后,必须在系统崩溃时显示第四个文档。 我在https://github.com/GroundMeteor/db/issues/184

上发现了一些可能相关的问题

有人能指出这个动态查询如何完成涉及$ where where with reactive vars,保持其自然反应性?

1 个答案:

答案 0 :(得分:1)

看起来你没有正确地设置你的反应变量。您不能只调用myReactiveVar.get() - 它们(通常)会附加到模板实例,因此您的代码应为:

pendingMTs帮助中,您使用const instance = Template.instance();访问该实例,然后在$where函数中使用instance.currentMonth.get()instance.currentYear.get()

在事件中,事件的第二个参数是模板实例,因此您将拥有:

'change #monthForecast' (event, templateInstance) {
    event.preventDefault();
    const target = event.target;
    templateInstance.currMonth.set( target.value );
},

所以你离得太远了!

https://docs.meteor.com/api/reactive-var.html

https://themeteorchef.com/tutorials/reactive-dict-reactive-vars-and-session-variables