meteor / meteor/blaze

#each re-rendered with stale data context

Open
#468 0 comments 0 reactions 0 assignees Claimed by @dupontbertrand View on GitHub
bug
Dominant language
JavaScript
Stars
543
Forks
117
Avg merge
6h 18m
Merged PRs (30d)
2

Description

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.
```js
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
```html

{{> eachTestChild foo=$tpl.foo.get }}

{{#each $tpl.getMsgs}}


Msg {{ msg }}
{{$tpl.log msg }}

{{/each}}

```
```js
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); },
});
});
```

Contributor guide

Open the contributing guide

Research direction

Start with the minimal Blaze test reproduction in the issue and trace the #each re-rendering path alongside Template.currentData() and the child view's data context. Done means the reproduced update no longer logs a stale view value and a regression test covers the expected data-context behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.