Skip to content
New issue

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

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

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

No branches or pull requests

2 participants