Using global state across multiple routes


#1

I am building an ember app which needs to keep some dates in its ‘global’ state, these dates will be set by a date picker. The date picker can be used on multiple routes if I select a date on /departments then when I navigate to users/2 the same date should be applied.

Selecting the date from the date picker should also trigger query params to update some ember-data models and fetch new data, the same for if I navigate pages, the data fetched should include the query params of the global state attached to the request.

Please see this wireframe for a simple example of the above: https://wireframe.cc/2iwb7j

What is the correct way to achieve this? Should I on change of the date picker send out an action and handle that in the controller for each page, this controller then sets the values on a service? Thus acting as global state, or is there a better ember way?

Thanks


#2

The service option Services are usually a good candidate for any application-level state. You may already be aware of all this but one of the nice things about a service is that you can set properties on a service and you can observe those properties from anything that injects the service. So if your service looked like this:

//services/date-service.js
import Ember from 'ember';

export default Ember.Service.extend({
  someDate: <a date>

  setSomeDate(newDate){
    this.set('someDate', newDate);
  },
  ...
});

Then you could observe that value anywhere you have the service injected:

export default Ember.Controller.extend({
  dateService: Ember.inject.service(),

  myDate: Ember.computed('dateService.someDate', function(){
    // you could update your query params here, or this could even be your query param maybe?
    return this.get('dateService.someDate');
  }),
});

And you can use it the same way in your template:

{{!-- these two are essentially the same}}
{{dateService.someDate}}
{{myDate}}

Then in the datepicker change action you could do something like:

this.get('dateService').set('someDate', newDate);

or

this.get('dateService).setSomeDate(newDate);

which of course would update the global date value on the service.

The application route solution I should give a big fat disclaimer here that I haven’t fully considered the implications of this and may not understand your use case well enough, but you could also consider (if this datepicker will be on every single view of your application) putting it in your application route/template/controller and then using application route query params. I guess you could also have a parent route that contains the datepicker and sets the value on it’s own model and/or controller, and then the child routes get said value (via modelFor, controllerFor, etc). I think the application/parent route could also update its query params that way. Again not sure how well that would work in practice but might be worth playing around with.


#3

Thanks for the response @dknutsen.

I recently wrote a blog post on how I achieved this https://joshhornby.co.uk/blog/ember-and-global-query-parameters

It seems you can’t just use any computed property on query params, it must be a computed .alias

Thanks for your help.