We’re actually finding an issue with Tracker.guard
(yes, I know it’s four years later
). Just thought I’d throw it in here to see if it clicks with anyone.
Say we have a highly reusable Blaze table template for viewing table data that takes an object of columns
that is defined by the table’s parent like so:
{{> dataTable extendContext columns=getColumns}}
We have a simple helper:
getColumns: function() {
return Template.instance().columns;
}
And then we have an autorun
that updates the columns
based on a data field tableFormat
from the main data context document from collection Items
:
instance.autorun(function() {
const tableFormat = Tracker.guard(() => Template.currentData().tableFormat);
switch(tableFormat) {
// Rebuild the columns object based on the current table format
instance.columns = ...;
}
});
Using Tracker.guard()
I’m noticing that if we use Tracker.guard()
the child table will re-render correctly only once based on the updated columns
object definition. Then after the first correct re-rendering, the table will always be one update behind.
For example:
- Upon load,
tableFormat
specifies a table with 5 columns and a 5-column table is created.
- Then
tableFormat
is updated to specify an 8 column table, the table will update correctly to an 8 column table.
- Then if
tableFormat
is updated to specify a 4 column table, nothing happens.
- Then if
tableFormat
is updated to specify a 7 column table, the table will update to be a 4 column table.
- And so on, with the updated table always being one update behind.
The weird thing is if I log tableFormat
within the autorun
, it’s always updated correctly. It’s the dataTable
template’s rendering that is always behind one update.
Using Template.currentData() Only
If I replace the above Tracker.guard()
line with just:
const tableFormat = Template.currentData().tableFormat;
The table updates perfectly upon every update to tableFormat
. However, the problem with this (as I mention above in several posts back) is that every field (e.g. title
, updatedAt
, etc.) on the main data context Item
(which has a lot of fields) will trigger this autorun
to re-run. And all those other fields have nothing to do with this block of code. So we don’t want that. Otherwise we’d have autoruns
firing everywhere.
Using Minimongo (Current Solution)
Upon a lot of experimentation, it seems like just doing a mini-mongo query within the autorun
is the solution that works the best. As it always updates the table correctly and it doesn’t rerun the autorun
when other fields change. So if I replace the above Template.currentData()
line with:
const currentItem = Items.findOne({_id: itemId}, {fields: {tableFormat: 1}});
It all works correctly.
My question is… why? Why does Tracker.guard()
go into a state where it’s always one update behind?