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.
refreshModel
replaces the neededthis.refresh
in thequeryParamsDidChange
action handler. Adds a more fine grained option and a proper API.As I tried to describe through Twitter stickiness could sometimes be the desired behavior or it should be possible to emulate it.
My use case was (something similar to):
The posts route renders a paginated list of posts (QP page). After clicking a post you can view the details on the post route. In the post template I wanted to link back to the posts route with the last active page QP. In that way the user can continue browsing the posts list from the last position/page.
This works out of the box in the current canary version due to the stickiness of QP. How could this behavior be emulated with your proposal? I believe we would need to loop through the QP from posts to post. Just to be able to set the page QP on the link-to from post afterwards.
In Posts Template
In Post Template
Not very elegant, but would work this way, right?