Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

#each re-rendered with stale data context #468

Open
josherich opened this issue Aug 18, 2024 · 0 comments
Open

#each re-rendered with stale data context #468

josherich opened this issue Aug 18, 2024 · 0 comments
Labels

Comments

@josherich
Copy link

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); },
  });
});
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants