Global Query Params

What is the correct way of having multiple routes share the same query param?

Say I have a queryParam for a city. Once that’s set, I’d like that any of the three routes that I have, use the city value that was already set, but still allow changing from any route.

Initial thought was using a computed property with a get / set and a service, but computed doesn’t appear to work as a query param.

1 Like

Can you share more about your route structure?

If all the routes you want to share with are siblings, you could store the query param on a parent route. Worst case, you could use the application route/controller

As an example, say I have these routes:

  • issues
  • orders
  • users

They are siblings and both have the city query param.

Yeah typically moving them up to the parent route makes the most sense as @NullVoxPopuli mentioned. Another thing you could try is binding them to service properties directly, e.g. in your controllers:

  location: service(),
  queryParams: {
    'location.city': {
      as: 'city'
    }
  },

Then you should be able to get/set those service properties per usual.

I tried both:

queryParams: {
  'location.city': {
    as: 'city'
  }
}

and

queryParams: {
  'location.city': 'city'
}

The route doesn’t update the model, despite working fine when using local (on the controller) city value.

Moving these queryParams to application (parent route) doesn’t help if I can’t bind the value in the child controllers, since I want the UI to be part of the child routes.

What do your route and “location” service look like?

// services/location.js

import Service from '@ember/service';

export default Service.extend({
  city: null
});
// routes/orders.js

import Route from '@ember/routing/route';

export default Route.extend({
  queryParams: {
    city: { refreshModel: true }
  },

  model(params) {
    return this.store.query('order', params);
  }
});

@dknutsen ideas? Do you have a repository using this feature that I can look at?

I was playing around with it yesterday. When I’d used the service binding before I only used it in controller scope, looks like for some reason if you also add the query param to the route it clobbers the controller binding or something. So I guess that solution won’t work right if you need the QPs to reload your route. Very annoying.

That said you could still put it on application controller, inject the application controller, and the bind to the QP there:

// child controller
import Controller from '@ember/controller';
import { inject as controller } from '@ember/controller';

export default Controller.extend({
  application: controller(),
});

// child template
{{input value=this.application.city}}

Ugly and annoying yes but it gets the job done. I think QPs are one of the more common pain points in Ember so I’m hoping they’re on the short list for refactor.

1 Like

I’m having trouble with this approach. I moved my QP to the application controller, which I assume is the parent, but the sibling routes don’t seem to get the param in the model signature:

controllers/application.js
controllers/projects.js

// projects.js
model(params) {
  console.log(params); // {}
}

Do I need to just access that information from the transition argument: model(params, transition)

EDIT:

You should be able to use paramsFor, Route - 4.6 - Ember API Documentation

Gah, duh! Thank you.