Changing query params in transitionTo doesn't seem work

Here is an example from the doc: https://guides.emberjs.com/release/routing/query-params/

// if you want to transition the query parameters without changing the route
this.transitionTo({ queryParams: { direction: 'asc' }});

I am in my application route and have query-params defined in its controller. To make things more concrete, let’s say they are city and state, and that I have specified their default values to be an empty string: ‘’.

The route I want to end up in is a few levels down, but I am putting the logic in the application's beforeModel hook. (Don’t think any of this makes a difference, but we’ve all been bitten by thinking that from time to time.)

Let’s say the q-p’s are {city: 'Boston', state: 'MA'}. I want to remove them from the browser’s address bar.

The doc says:

If you wish to reset a query param, you have two options:
1) explicitly pass in the default value for that query param into link-to or transitionTo.

So at the end of my beforeModel hook I set them to the default values like so: this.transitionTo( { queryParms: { city: '', state: ''} } );

I end up on the right page, but unfortunately the query params are still in the URL. And when I do something like this: this.transitionTo( { queryParms: { city: 'New York', state: 'NY'} } ); the original query params {city: 'Boston', state: 'MA} are still in the URL.

Also, the console shows an error on the transitionTo statement. In Firefox it’s: TypeError: routeInfos[(routeInfoLength - 1)] is undefined,

while Chrome spits out:

Uncaught (in promise) TypeError: Cannot read property 'name' of undefined
at Class._queryParamsFor (router.js:835)
at Class.finalizeQueryParamChange (route.js:2128)
at Class.triggerEvent (router.js:1290)
at PrivateRouter.triggerEvent (router.js:175)
at PrivateRouter.finalizeQueryParamChange (router_js.js:1933)
at PrivateRouter.queryParamsTransition (router_js.js:1427)
at PrivateRouter.getTransitionByIntent (router_js.js:1496)
at PrivateRouter.transitionByIntent (router_js.js:1445)
at PrivateRouter.doTransition (router_js.js:1579)
at PrivateRouter.transitionTo (router_js.js:2057)

If I comment out the transitionTo statement the error messages disappear.

It seems like this should be a simple thing to do, yet I have spent hours trying to figure out how to get rid of the query params in the browser’s address bar. Am I doing something wrong, or do the console error messages indicate some kind of problem?

Off the top of my head this sounds like it could be caused by trying to call transitionTo in the middle of another transition. In the guides it mentions that this will “implicitly abort” the transition. Also if you put this logic in the application route’s beforeModel hook I’d think it would only be executed once (which maybe is what you want, but if not that could be a problem).

When you say “The route I want to end up in is a few levels down” how are you getting to that route? Via link-to? or transitionTo? That would be my first thought as to where to clear the QPs. If that’s not possible you could probably clear them via the application controller, perhaps either in the willTransition hook of the application route or maybe the beforeModel hook of the destination route would even work, not 100%.

Anyway I’m just taking a couple shots in the dark here.

Oh another thing I’ve done before is bound query params to properties on a service, and then you can inject the service and clear the properties wherever you want. I’m not sure if this is 100% within the confines of the query param design but it seemed to work ok. Let’s say you did this in your application controller, would look something like:

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

Then anywhere you update the city/state params on the location service it would update the query params.

You may have tried this already but you could also try the resetController hook instead of beforeModel.

Thanks for the quick reply. That’s one of the things I love about the Ember community: it seems everyone helps whenever they can.

Addressing the points that you made:

I am getting to the nested route from an external link, e.g. a link in an email. That’s why I have the logic in the beforeModel hook of the application route - this logic/transition is going to take place but one time - when the app is initially loaded.

I saw an example of using transitionTo in the afterModel hook in Ember’s API Guide, so I figured it was okay to put the same statement in the beforeModel hook. (BTW, I tried putting it in the afterModel hook and that didn’t work, either. It also displayed the same error messages in the Firefox and Chrome consoles.)

Aborting the current transition is fine with me, as calling transitionTo without a route as an argument will just transition to the same route. Which is what I want.

Also, I didn’t put the call to transitionTo in the nested route itself, because a bunch of models were loaded on the way down to it, and I couldn’t see doing that again. Besides, it seems like it shouldn’t make a difference. (Famous last words, right? :wink: )

And it seems that clearing the query params via a call to transitionTo is the way to go, because, according to the docs, the only other way to do that is through logic in resetController, and I don’t think one ever exits from the application route, right?

So it seemed the place to put my logic was in the application route model hooks. The external email link contains query-param info (user info and token) to automatically log the user in when the app is fired up.

I use ember-simple-auth. (Thanks simplabs!) Normally I talk to a Rails back-end through an ember-simple-auth Devise authenticator. This works fine for the standard Username and Password login page, but not so good for automatic log-in from an external link. So I had to write my own custom authenticator for ember-simple-auth.

I have all of this working, i.e. the email contains a nested link that results in the user seeing a page specifically for him, and on that page are things that only a logged-in user can see, e.g. he can see the comments, and since he is logged in, there is a Submit Comment button that is visible. (That’s not actually what I do, but it’s an illustrative example that everyone can understand.)

So, like I said, it’s all working, except that the query-params - which include an authenticity token for this specific user - are still visible in the browser’s address bar.

It seems like it should be soooo simple to clear them out, but I have spent over a day on this trying all different solutions and just cannot get rid of the original query params that were presented when firing up the app.

Any more thoughts would be greatly appreciated, as I am pretty much at my wit’s end on this.

Thanks, Larry

A couple of general points:

  1. I have my code in the application route’s beforeModel hook because that is where ember-simple-auth had theirs. And it makes sense to put it there because I want a currentUser as soon as possible, i.e. so the following routes/templates in the route hierarchy contain the correct things, e.g. I want to see Account Settings instead of Log In on the menu for a logged-in user.

  2. Once I have authenticated the user I no longer need, nor want to see, the query params that I used for authentication. So I figure I can just transitionTo the same route, but with a queryParams hash that sets the params to their default values, which means they should disappear from the URL. Not only does this not happen, but, like I said, when I changed the values of the parms, those changes did not appear in the URL.

  3. The docs show an example of calling transtionTo in an afterModel hook. They also show examples of calling transtionTo with only a queryParams: { ... } argument. When I did that, both Firefox and Chrome showed errors in the console (which are shown above) - so maybe that is why this stuff is not working?

Well, I added a query param called ‘xxx’ to the leaf route in question, i.e. not ‘application’.

I called it with a q-p value in the URL of ?~~~<other q-p’s> ~~~&xxx=123.

Then in the beforeModel hook of the leaf route I have this one line:

this.transitionTo( {queryParams: {xxx: '456'} })

which, according to the doc in both the Guides and API should

// if you want to transition the query parameters without changing the route

Not only does the q-p not get changed to ‘456’, but I get the console errors mentioned in the post that kicked off this thread.

Can someone please tell me if it is a bug? Or if and/or how I should bring it to someone’s attention?

My guess was that since it’s interrupting the transition (which is fine) with another, BUT the new transition doesn’t specify a route to transition to, it doesn’t necessarily continue the transition from before and therefore has no idea where to go.

Also query params are often used in route models so if you’re going to do this anywhere I’d think you’d want to do in afterModel or setupController.

So It’s definitely possible it’s a bug, but at a conceptual level it seems like something that could cause problems anyway.

because, according to the docs, the only other way to do that is through logic in resetController

I don’t think this is necessarily true. Yes, that’s all the docs mention in regards to the subject, but you should definitely be able to clear them via other methods. You said you’re binding them to props in your application controller, so you should be able to clear them from anywhere by injecting the application controller (or using a service like I described above).

EDIT: if this helps at all I think query params are a very common source of frustration (so you’re not alone) and are on the radar for some serious refactoring. I think @NullVoxPopuli recently published an addon related to query params…

Hi Dan,

Again, thanks for thinking about this and replying with your thoughts on the matter.

Regarding not specifying the transition and therefore not having any idea where to go: I always end up on the right page, with the right content (i.e. fetched models). Also, the comments in both the Guide and API docs imply that this is the way to change the query params without changing the route. (BTW, I also tried changing the value of the q-p’s to the default values in an attempt to clear them out, but that did not work, either.)

Also, the reason I said I have spent hours on this is because I have tried the things you mentioned: I have put the logic in the afterModel and setupController hooks, to no avail.

I have also tried using resetController - nada.

And - a la your suggestion of trying other ways not mentioned in the doc - one of the first things I tried was to specifically set the q-p’s to different values, including the defaults in order to clear them out, by doing something like

this.controllerFor('application').set('xxx', 'abcdef')

In the before-and-after-Model and setupController hooks in both the application and leaf routes… and nothing worked.

Again, this seems like it should be so simple: Given the classic URL, e.g.

/users/3/posts/7/comments?sky=blue&grass=green

in the initial entry to the app (i.e. beforeModel hook in the application route) or any before-or-after-Model or setupController route hook in any of the routes on the way down to the leaf route, I am just trying to say (via the code):

I want to use those query params of yours for something. When I’m done, I no longer need them, and I don’t want to see them in the final URL. So I’m gonna yank 'em outta there, and you just continue on to where you were going before I interrupted your (routing) journey.

And I simply Cannot. Yank. Them. Outta. There.

Anyway, thanks for your help. I think I’m just going to have to bail on this because I’ve spent too much time on it and my head is spinning and I’ve got a ton of other stuff to do. (Just like every other developer, eh? :wink: )

P.S. I wonder if the fact that this happens during the initial firing-up of the app, as opposed to executing a linkTo in an app that’s already been downloaded and initialized, has anything to do with the problems I am having.

I don’t know. Maybe stepping away will clear my head.

Ah gotcha, didn’t realize you’d already tried all of that, sorry! That is definitely more puzzling. Like I said QPs don’t have the best reputation in Ember but I’ve never seen anything quite like that. The only thing I can think of to check other than that is that your query param bindings are set up correctly :thinking: anyway hope taking a step away helps, often helps me. Good luck!

Hey man, don’t apologize for offering sound solutions - if anything they made me feel better for trying things that made sense and had a good chance of working.

Also, I had so many commented-out statements in so many methods that I very well may have stumbled upon a correct solution - but the interplay of un-commented statements (some of which I probably assumed were commented out) may have sabotaged the effort. I think we’ve all seen code that we could’ve sworn we commented out… but didn’t. aarrgghh!! :scream:

And you are right about stepping away. Or taking a shower. Or sleeping on it. The brain is an amazing thing, that’s for sure.

Thanks again, Larry

An update, in case anyone ends up here: ember 3.11 was just released today, so I tried the query-params addon by @NullVoxPopuli (since @dknutsen was nice enough to point it out to me). (The addon dependency was v3.11)

It didn’t work. And in one case it made matters worse in that it fostered a TypeError: transition.to is null error.

I think this has something to do with ember-simple-auth because I can wipe out the query params if the user is not logged in, however, if he is logged in the query params remain.

ember-simple-auth jumps through a fair number of hoops that differ when the user is and is-not logged in. Several debugger sessions did not result in me getting a grip on what is happening and how to fix it.

Oh well, that’s the way it goes sometimes.

Thanks for your help @dknutsen