[BUGFIX] @model becomes undefined or changes to the wrong route's model during Glimmer component willDestroy#21203
[BUGFIX] @model becomes undefined or changes to the wrong route's model during Glimmer component willDestroy#21203johanrd wants to merge 6 commits intoemberjs:mainfrom
@model becomes undefined or changes to the wrong route's model during Glimmer component willDestroy#21203Conversation
When transitioning between routes, the @model argument on a Glimmer component becomes unstable during willDestroy - the model value changes before the component is properly destroyed. Requires @glimmer/component Vite alias to resolve in tests. Based on PR emberjs#20959 by @Windvis.
When transitioning between routes, @model becomes undefined in Glimmer component willDestroy hooks. The existing guard (lastState === state) only detects outlet changes at the same level. When a parent outlet tears down first, the dynamic scope refs silently redirect to the new route's outlet state while the guard still passes. Add a controller identity check so the model ref detects when its outletRef has been redirected to a different route's data. Fixes emberjs#18987
…nternal @glimmer/component import isn't necessary in vite.config
| named['controller'] = createConstRef(state.controller, '@controller'); | ||
|
|
||
| // Create a ref for the model | ||
| let modelRef = childRefFromParts(outletRef, ['render', 'model']); |
There was a problem hiding this comment.
I think something along this vein is the real fix:
| let modelRef = childRefFromParts(named['controller'], ['render', 'model']); |
The modelRef should only depend on the constant controller, not the variable reference to the controller.
There was a problem hiding this comment.
@ef4 Thanks, tried now (if I understood correctly): I get two test failures with something like that: https://github.com/johanrd/ember.js/actions/runs/22914352893/job/66495351782?pr=11
I guess we can be okay with @model tracking controller.model mutations? If yes, we may update the tests (bugfix, or RFC)?
There was a problem hiding this comment.
I got 33 failures https://github.com/emberjs/ember.js/actions/runs/22912061404/job/66486942647?pr=21215 🙈 ope
Concerns over @model updating during same-route transitions
|
Summary
@modelbecomesundefined(or changes to the wrong route's model) during Glimmer componentwillDestroywhen transitioning between routeslastState === stateguard in the outlet helper's model compute ref@modelis stable between route transitions #20959 by @Windvis)Details
The
@modelreference in route templates is built from a chain of compute refs that read from the shared outlet state tree via dynamic scope. When transitioning,_setOutlets()rebuilds this tree, and all refs in the chain immediately see the new state.The existing guard (
lastState === state) freezes the model value when the outlet changes at the same level. But when a parent outlet is torn down first, the child outlet's outer compute ref never re-evaluates, solastStateis never updated. The guard passes, andmodelRefreads from the wrong outlet state.The fix compares the current outlet's controller identity against the expected one. Since each route has a unique controller singleton, this detects when the
outletRefhas been redirected — even whenlastStatehasn't been updated yet.From git history, the bug may have existed since
@modelwas introduced in v3.14.0 (16b74a5). The original implementation read directly from theoutletRefchain with no guard at all. ThelastState === stateguard added in v4.0.0 (commit 7d334cf) partially mitigated same-level transitions but did not catch parent-level teardown.Fixes #18987
Supersedes #20959
Test plan
smoke-tests/scenarios/basic-test.ts: transitions through sibling, parent, cousin, and unrelated routes, verifyingthis.args.modelinwillDestroyBased on Add a test that verifies@modelis stable between route transitions #20959 but moved to smoke-test to avoid the vite.config import of glimmer-componentBefore the fix, the added smoke tests fail with:
workspace:*(with fix)~6..11.0~5.12.0~4.0.0~3.28.0Cowritten by claude