blaze
blaze copied to clipboard
#each re-rendered with stale data context
Tested in Meteor 3.0.1 MacOS 14.6.1 expected behavior: data context in view should be the same as currentData while re-rendering actual behavior: data context in view is stale while re-rendering
Here's the minimal reprod using Blaze test code:
In the test code, the final buf
shows
[
"getMsgs called: foo",
"view:foo, data:foo",
"---flush---",
"getMsgs called: bar",
"view:foo, data:bar", <------------- foo in view, but bar in currentData
"view:bar, data:bar"
]
I'm not 100% sure if this is a bug or expected behavior, but it can cause confusion since it's a very common pattern.
Blaze.Template.registerHelper('$tpl', function() {
return Blaze.Template.instance();
});
const R = ReactiveVar('foo');
const buf = [];
const eachTest = Blaze.Template('eachTest', function() {
var view = this;
return Blaze._TemplateWith(function() {
return {
foo: Spacebars.call(Spacebars.dot(view.lookup("$tpl"), "foo", "get"))
};
}, function() {
return Spacebars.include(view.lookupTemplate("eachTestChild"));
});
});
eachTest.onCreated(function() {
const tpl = this;
Object.assign(tpl, {
foo: R,
});
});
const eachTestChild = Blaze.Template('eachTestChild', function() {
var view = this;
return Blaze.Each(function() {
return Spacebars.call(Spacebars.dot(view.lookup("$tpl"), "getMsgs"));
}, function() {
return ["\n ", HTML.DIV("\n Msg ", Blaze.View("lookup:msg", function() {
return Spacebars.mustache(view.lookup("msg"));
}), "\n ", Blaze.View("lookup:$tpl.log", function() {
return Spacebars.mustache(Spacebars.dot(view.lookup("$tpl"), "log"), view.lookup("msg"));
}), "\n "), "\n "];
});
});
Blaze.Template['eachTestChild'] = eachTestChild;
eachTestChild.onCreated(function() {
const tpl = this;
Object.assign(tpl, {
getMsgs() {
const foo = Template.currentData().foo;
buf.push('getMsgs called: ' + foo);
if (foo === 'foo') {
return [{_id: '1', msg: 'foo'}];
} else {
return [{_id: '2', msg: 'bar'}];
}
},
log(foo) {
buf.push('view:' + foo + ', data:' + tpl.data.foo);
}
});
});
const div = document.createElement("DIV");
Blaze.render(eachTest, div);
R.set('bar');
buf.push('---flush---');
Tracker.flush();
console.log(buf);
Here's the app code
<template name="eachTest">
{{> eachTestChild foo=$tpl.foo.get }}
</template>
<template name="eachTestChild">
{{#each $tpl.getMsgs}}
<div>
Msg {{ msg }}
{{$tpl.log msg }}
</div>
{{/each}}
</template>
Template.eachTest.onCreated(function() {
const tpl = this;
Object.assign(tpl, {
foo: new ReactiveVar('foo')
});
});
Template.eachTestChild.onCreated(function() {
const tpl = this;
Object.assign(tpl, {
getMsgs() {
const foo = Template.currentData().foo;
console.log('get msgs', foo);
if (foo === 'foo') {
return [ { _id: '1', msg: 'foo' }];
} else {
return [ { _id: '2', msg: 'bar' }];
}
},
log(foo) { console.log('view:', foo, ', data:', tpl.data.foo); },
});
});