Skip to content

Redirecting a transition to same route with different query params does not work unless transition is aborted before #18577

Open
tildeio/router.js
#307
@jelhan

Description

@jelhan

I'm seeing two weird bugs if doing a redirect to the same route with different queryParams in beforeModel hook:

  1. If the route is entered via <LinkTo> or transitionTo(), the query param is not reflected in the URL.
  2. 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:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions