Reputation: 21
This is about a problem with a helper containing a dynamic query that involves reactive vars and the $where operator that does not rerun when the reactive vars values are changed. Then about how a try to solve it lead to a strange system behavior and crash.
I have a template in which we want to show a list of found documents inserted within an #each loop:
<template name="todo">
{{#each pendingMTs}}
<button class="showPendMT">
<h4> - <strong> {{name}}</strong> </h4>
</button>
{{/each}}
</template>
The pendingMTs helper searches for the documents in the Tasks collection with a dynamic and somehow elaborate -here simplified- query that involves using the $where operator:
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; }}
]
});
}
The two reactive vars involved in the search are defined at the creation of the template:
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);
});
Then in an event handler we modify the reactive vars upon a 'select' change, for instance for the currMonth:
'change #monthForecast' (event) {
event.preventDefault();
const target = event.target;
currMonth.set( target.value );
},
The first issue is that the helper is not rerun despite we modify through the event handler the value of the reactive vars: WHY??
Thinking that this might be due to the fact that the reactive vars are inside the $where function, I added a simple line at the beginning of the helper in order simply to create awareness for them in the helper:
var rerun = currYear.get(); rerun = currMonth.get();
Now certainly that made the helper to rerun any time any of the 2 reactive var was changed. But unfortunately this lead to a very strange behavior:
When the modified reactive vars caused the helper to retrieve one more document than the number of documents retrieved the first time, the system crashed (and therefore the new document was not shown in the #each template):
Exception from Tracker recompute function: meteor.js:930:11
Error: Bad index in range.getMember: 3
While looking for the cause I found out that the bad index number given, 3 in this case, is always equal to the number of documents retrieved the first time the helper was executed. In this case, after modifying the value of one of the reactive vars, a 4th document had to be shown when system crashed. I found some maybe related issues on https://github.com/GroundMeteor/db/issues/184
Could anyone point out how this dynamic query involving $where with reactive vars could be done, maintaining its natural reactivity?
Upvotes: 1
Views: 50
Reputation: 2236
Looks like you're not getting and setting your reactive-vars properly. You can't just call myReactiveVar.get()
- they are (usually) attached to the template instance so your code should be:
In the pendingMTs
helper, you access the instance with const instance = Template.instance();
and then in your $where
function you would use instance.currentMonth.get()
and instance.currentYear.get()
In the event, the second argument of the event is the template instance, so you would have:
'change #monthForecast' (event, templateInstance) {
event.preventDefault();
const target = event.target;
templateInstance.currMonth.set( target.value );
},
So you're not too far off!
https://docs.meteor.com/api/reactive-var.html
https://themeteorchef.com/tutorials/reactive-dict-reactive-vars-and-session-variables
Upvotes: 1