Skip to content

Instantly share code, notes, and snippets.

@jamesarosen
Last active February 19, 2016 20:42
Show Gist options
  • Save jamesarosen/f170ee1aca5f1f455c6e to your computer and use it in GitHub Desktop.
Save jamesarosen/f170ee1aca5f1f455c6e to your computer and use it in GitHub Desktop.
Trouble with Ember 1.13 Query Params

Some notes on problems I'm experiencing with Ember's Query-Params.

Background

I'm trying to create a "global" query-param that exists on controller:application and sticks around for the whole session. An example might be http://myapp.com/some/route?locale=es. The only oddity is that only some users are allowed to set this parameter; for other users, it's ignored. I started with the following

// app/pods/application/controller.js
export default Ember.Controller.extend({
  queryParams: [ 'locale' ],
  
  locale: Ember.computed({
    get() { return undefined; },
    set(prop, newValue) {
      return userCanSetLocale ? newValue : undefined;
    }
  }
});

First Transition

Ember is supposed to keep the URL representation (?foo=bar) and the controller representation (controller.get('foo')) in sync. That sync hasn't happened on the first transition. In order to reliably access this.controllerFor('something').get('foo') in all transitions, I need to add the following to my route:application:

const FixQueryParamsOnBoot = Mixin.create({
  // Ember doesn't copy query params from the transition to the
  // controller until the end of the transition. Call this to ensure
  // they're properly initialized.
  beforeModel(transition) {
    const controller = this.controllerFor('application');

    controller.getWithDefault('queryParams', []).forEach(function(key) {
      if (controller.get(key) != null) return;
      controller.set(key, transition.queryParams[key]);
    });
  }
});

// app/pods/applicaton/route.js:
export default Route.extend(FixQueryParamsOnBoot, {

  beforeModel() {
    initializeSession().then(() => {
      return this._super(...arguments);
    });
  }

});

refresModel Incompatible with Symbolic Transitions

If I specify

// app/pods/application/route.js
export default Ember.Route.extend({
  queryParams: {
    foo: { refreshModel: true }
  }
});

then I can't use transitionTo('symbolic.route') or Ember will complain that it can't find enough dynamic segments. See http://discuss.emberjs.com/t/queryparams-how-to-satisfy-dynamic-segments-for-route/6714

Instead, I have to not mark foo as refreshModel: true and instead use a manual this.refresh() call.

Query Params Lost on transitionTo

Let's say I have a global query-param (declared on controller:application). If I have a route that redirects to another route:

// app/pods/something/route.js
export default Ember.Route.extend({
  beforeModel() {
    this.transitionTo('something.else');
  }
});

then the query-param is lost from the URL when I transition. The smallest solution I've found is

// app/pods/application/route.js

export default Ember.Route.extend({
  // Override Ember's default implementation to fetch from the
  // controller:
  serializeQueryParam(value, key, ...args) {
    // Query params on controller:application seem to get obliterated
    // on every transitionTo, replaceWith, and link-to call. The problem
    // might be the HistoryLocation or our <base> tag, or something else.
    // This is the smallest fix, though it won't work with query params
    // that use "as" to map the query-param name to a URL param.
    value = value || this.controllerFor('application').get(key);
    return this._super(value, key, ...args);
  }
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment