It's amazing, but not good enough.
Consider:
App.PeopleController = Ember.ArrayController.extend({
queryParams: ['page'],
page: 1
});
Here's what's wrong with the above:
- As the url changes,
page
will become a string (e.g. "2", "3", etc), so you have to do a lot ofparseInt
ing if you need it to be treated as a number, which is obviously annoying. page
property is annoyingly sticky; if youlink-to 'people'
and don't specify QP props in thequery-params
sexpr, the first transition into it will use the default value of 1, but if you change the value ofpage
to '2', navigate away, and click that samelink-to
to get back into 'people',page
stickily retains its value of '2' on the grounds thatlink-to
doesn't specify any QP values to override. This is very bizarre, see a more detailed explanation here- Having all this stuff on controllers contradicts our goal of getting the lazy-loading of routes/controllers/templates/sections of your app.
App.PeopleRoute = Ember.Route.extend({
queryParams: {
peoplePage: {
defaultValue: 1,
// default is false; `replace: true` means that when a controller
// changes `queryParams.peoplePage`, the URL will be updated
// via replaceState rather than the default pushState.
// (fwiw: this mimics the existing api of `link-to 'people' replace=true`)
replace: true,
// default is false; this opts into a full transition when
// this QP changes.
refreshModel: true
}
}
});
App.PeopleController = Ember.ArrayController.extend({
// This is how controllers can pick a more appropriate
// name/interface for a query param prop; the router
// knows it as its url-serialized key `peoplePage`,
// but the PeopleController can just call it `page`
page: Ember.computed.alias('queryParams.peoplePage')
});
Here's how this fixes the above concerns:
- When the url changes to
?peoplePage=123
, we can infer from the default value to deserialize into a number, soPeopleController
seesqueryParams.peoplePage
as123
rather than"123"
. - Things are appropriately less sticky; if you link to a route without
specifying a QP value (via
query-params
sexpr), and there's no serialized key-value pair in the URL already, then clicking that link will 1) not even bother serializing anything into the final URL for that QP, 2) the controller will seequeryParams.peoplePage
as thedefaultValue
specified, ornull
if none specified. link-to
won't require eager Controller initialization (or prototype hacks); if you saylink-to 'people' (query-params lol="wat")
, it'll serialize an href of "/people?lol=wat" even if that qp is totally unused (thereafter, if you click a link elsewhere, the lol=wat will disappear from the url unless someone claims it).
Other implications
link-to
will have to specify Route-level query param keys, rather than the present day of specifying property names of controllers in destination route hierarchies.
Adding the possibility to describe QPs in the route a QP belongs to is definitely a good choice. I think it's better to give the option to specify every detail instead of having only pre-defined behavior which may prevent the feature from being used. Also, custom serializers/deserializers as the last resort would be much appreciated.
As I wrote down my points, I had not even thought about the problem with stickiness, but (as far as I understand your explanation), this seems quiet reasonable.
One thing I want to make sure is not forgotten regarding the defaultValue: When a QP takes its defaultValue, it should not be visible in the URL, right? This is an important thing when trying to keep clean URLs while having many QPs on one route.
Also (but this may be a more handlebars related question): With @alexspeller's implementation of queryParams it was possible to bind the whole QP-thingy in a link-to roughly like this:
{{#link-to "route" queryParams=params}}
where params is a hash generated in the controller. I used this to render a list of "predefined filters" by using{{each}}
and a list of controller-generated QP options. Would this be possible without listing every possible QP key in the(query-params)
subexpression like(query-param author=author search=search state=state ...)
?Again, thanks for your work and open discussion of this feature!