ember.js: Redirecting a transition to same route with different query params does not work unless transition is aborted before
I’m seeing two weird bugs if doing a redirect to the same route with different queryParams in beforeModel hook:
- If the route is entered via
<LinkTo>ortransitionTo(), the query param is not reflected in the URL. - If the route is entered directly on application start, ember throws an error.
The error thrown is this one:
TypeError: Cannot read property 'name' of undefined
at Class._queryParamsFor (https://t95pf.sse.codesandbox.io/assets/vendor.js:35740:59)
at Class.finalizeQueryParamChange (https://t95pf.sse.codesandbox.io/assets/vendor.js:34759:29)
at Class.triggerEvent (https://t95pf.sse.codesandbox.io/assets/vendor.js:36198:27)
at PrivateRouter.triggerEvent (https://t95pf.sse.codesandbox.io/assets/vendor.js:35078:43)
at PrivateRouter.finalizeQueryParamChange (https://t95pf.sse.codesandbox.io/assets/vendor.js:72248:12)
at PrivateRouter.queryParamsTransition (https://t95pf.sse.codesandbox.io/assets/vendor.js:71741:37)
at PrivateRouter.getTransitionByIntent (https://t95pf.sse.codesandbox.io/assets/vendor.js:71810:37)
at PrivateRouter.transitionByIntent (https://t95pf.sse.codesandbox.io/assets/vendor.js:71759:21)
at PrivateRouter.doTransition (https://t95pf.sse.codesandbox.io/assets/vendor.js:71894:19)
at PrivateRouter.transitionTo (https://t95pf.sse.codesandbox.io/assets/vendor.js:72372:19)
It’s caused by routeInfos of transition being an empty array here: https://github.com/emberjs/ember.js/blob/v3.14.1/packages/%40ember/-internals/routing/lib/system/route.ts#L2523 _queryParamsFor can’t handle that case and throws at this line: https://github.com/emberjs/ember.js/blob/v3.14.1/packages/%40ember/-internals/routing/lib/system/router.ts#L926
For a minimal reproduction use this code:
// app/routes/foo.js
import Route from '@ember/routing/route';
export default Route.extend({
async beforeModel(transition) {
if (!transition.to.queryParams.bar) {
await this.transitionTo('foo', { queryParams: { bar: "1" }});
}
}
});
// app/controllers/foo.js
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
router: service(),
queryParams: ['bar'],
});
// app/templates/foo.hbs
{{log router.currentRoute}}
The current route is logged in template to verify that the query params are available on RouteInfo object for scenario 1. And they are indeed. They are just not represented in URL.
Both bugs could be fixed by explicitly aborting the transition before doing the redirect:
// app/routes/foo.js
import Route from '@ember/routing/route';
export default Route.extend({
async beforeModel(transition) {
if (!transition.to.queryParams.bar) {
transition.abort();
await this.transitionTo('foo', { queryParams: { bar: "1" }});
}
}
});
But accordingly to documentation transitionTo() should implicitly abort the transition. It should not be required to do it manually. Also if this is the recommended solution, there should be an assertion if the transition is not aborted before. It should not end with a broken state (URL not reflecting query parameters in URL) neither with throwing a TypeError.
There are some issues which seem to be related but slightly different:
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 4
- Comments: 18 (13 by maintainers)
Commits related to this issue
- fix: qp-only transition during initial transition Seems to fix https://github.com/emberjs/ember.js/issues/18577. — committed to buschtoens/router.js by buschtoens 4 years ago
I have what appears to be an additional variant of this, available in this repo.
If you try to do a
transitionToorreplaceWithin a route’safterModel, and it’s a query-params-only transition, and it’s the first time entering the application (i.e. first render), it will fail with exactly the error @jelhan reported above. Moreover,transition.abort()does not fix things in this case; it just leaves you with a dead app. 😬To see the reproduction behavior and how it varies for later entries, comment out these lines: later transitions work fine; only the first transition into the route fails this way. To see that
transition.abort()only further hoses things in this case, comment those lines back out and uncomment this line.@acorncom I’m quite sure that I had reproduced it using the latest version of Ember at the same day when reporting. So I think it was 3.14.1. But I was also able to reproduce it with latest ember-source available today, which is 3.16.0.
I created a repository with the reproduction mentioned above: https://github.com/jelhan/ember-demo-redirect-to-same-route-with-different-query-params
Here are the steps to reproduce both issues mentioned above using that repo. Assuming that you have cloned it, installed dependencies and run
ember serve.1. transition to route triggering the redirect from another route
Expected:
currentURLproperty ofRouterServiceshould be/foo?bar=1currentRoute.queryParamsshould deep equal{ bar: 1 }Actual:
currentURLproperty ofRouterServiceis/foo(missing query param)currentRoute.queryParamsdeep equals{ bar: 1 }(correct but out of sync with URL)2. open that route directly
See an error been thrown and nothing rendered. The error is:
Fixing the error by aborting the transition
To reproduce that aborting the transition before doing the redirect fixes both issues uncomment these line: https://github.com/jelhan/ember-demo-redirect-to-same-route-with-different-query-params/blob/1326804684273b9369725099f36f262fabdd9832/app/routes/foo.js#L6-L7
Just encountered this on Ember 4.12. 😞 @buschtoens fix in tildeio/router.js#307 does seem to fix it for me, though. Pretty amazed this has gone so long without being addressed since it seems like a common scenario.
Anyone know of any workarounds or any way this could be monkey-patched?
We’re still seeing this issue in Ember.js 5.1.
If we’re replacing a route with the same route but different query params:
the route crashes on first render with:
Unfortunately none of the workarounds seem to work. Any suggestions on getting around the bug?
Same problem as @chriskrycho with ember 3.22.
Also cannot use
transition.abort()because it breaks the app when it’s a first render.@rreckonerr If I got it right you suspect that the bug was introduced by https://github.com/tildeio/router.js/commit/f385d1162ab3307c166bf5b6b19eef45345dd8d0. It was released in
router_js@5.0.0.Ember.js upgraded to
router_js@^5here: https://github.com/emberjs/ember.js/pull/17007ember-source@3.6.0is the first stable release containing this version: https://github.com/emberjs/ember.js/blob/a5f870fd309e5008667b3ca2bf569721ac3c2f96/package.json#L149 The stable release beforeember-source@3.5.1as usingrouter_js@2.0.0-beta.4: https://github.com/emberjs/ember.js/blob/abf753a3d494830dc9e95b1337b3654b671b11be/package.json#L139Will try to find some time to verify that the bug is reproducible with
ember-source@3.6.0but not withember-source@3.5.1. Theember-source@3.6.0contains many router related changes. But at least it would help to trace down the bug to that big router refactoring.