ember.js icon indicating copy to clipboard operation
ember.js copied to clipboard

[Bug] No way to reset query parameters when transitioning to the same page

Open fastfedora opened this issue 2 years ago • 5 comments

🐞 Describe the Bug

Ember uses sticky query parameters by default. To make a parameter non-sticky, the documentation says there are two options:

  1. explicitly pass in the default value for that query param into <LinkTo /> or transitionTo.
  2. use the Route.resetController hook to set query param values back to their defaults before exiting the route or changing the route's model.

However, when transitioning to the same page, both options must be used. It is not sufficient to merely reset the query parameters in Route.resetController.

More specifically, there is no way to reset all parameters when transitioning to a route, as Route.resetController only resets the parameters when transitioning from a route.

Explicitly passing in default values in <LinkTo /> or transitionTo will work, but is fragile, as it relies on the caller knowing what query parameters have been defined on the route.

🔬 Minimal Reproduction

See this Ember Twiddle for an example.

This is a simplified example of an issue we're having in our current application. The links are contained within a navigation menu, so shouldn't have any knowledge of the implementation of the profile page. However, the only link that works is when the navigation menu knows exactly what query parameters have been defined for the route.

😕 Actual Behavior

Query parameters are sticky, even if you attempt to make them non-sticky using Route.resetController, when transitioning to the same page.

🤔 Expected Behavior

There should be a way to specify query parameters as non-sticky so that links to a route don't require knowledge of what query parameters have been defined on that route to get a default view.

Ideally there would be a way to turn off sticky behavior by default for query parameters, either at the route level or for the entire application. For links, there should be a way to request a route without existing parameter values being copied into the request.

🌍 Environment

  • Ember: 4.7
  • Node.js/npm: 16.17.0
  • OS: Mac OS 12.5.1
  • Browser: Chromium 102.0.5005.63

➕ Additional Context

This is similar to issue #10260.

One workaround is to override the router service so that when an explicitly empty queryParams object is passed to initiate a transition, existing query parameters are not copied to the to transition:

// app/services/router.js
import { default as EmberRouterService } from '@ember/-internals/routing/lib/services/router';

export default class RouterService extends EmberRouterService {
  transitionTo(...args) {
    const query = args[args.length - 1]?.queryParams;
    const hasQuery = typeof query === 'object';
    const emptyQuery = hasQuery && Object.keys(query).length === 0;
    const routeOrUrl = args.length > 0 || !hasQuery ? args[0] : '';

    if (
      !emptyQuery ||
      !this.currentRoute ||
      this.currentRoute.name !== routeOrUrl
    ) {
      return super.transitionTo(...args);
    }

    const queryParams = Object.keys(this.currentRoute.queryParams).reduce(
      (params, key) => {
        params[key] = undefined;

        return params;
      },
      {}
    );

    return super.transitionTo(...[...args.slice(0, -1), { queryParams }]);
  }
}

With this change, <LinkTo @route="my-route" @query={{hash}}> would reset the query parameters, while <LinkTo @route="my-route"> would not.

This could be implemented directly within Ember with little disruption, since it's unlikely existing code is passing an empty hash into @query.

fastfedora avatar Sep 28 '22 13:09 fastfedora