Skip to content

optional query parameters shouldn't be removed from the url #539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
daanporon opened this issue Oct 30, 2013 · 22 comments
Closed

optional query parameters shouldn't be removed from the url #539

daanporon opened this issue Oct 30, 2013 · 22 comments
Assignees
Labels

Comments

@daanporon
Copy link

in my app i'm using a query parameter to define a second state of the app, there is a small part of the app that can load state next to the main state. This second state can be triggered everywhere so the main state and this second state are completely different. It's possible to give an url to this query parameter and the template + controller of this url will be loaded into this small part of the app. My url looks like this:

/my/main/state?context=/my/optional/second/state

The problem i'm having now is that whenever i browse to my url with my second state as query parameter, the query parameter gets removed. This is because it isn't defined in my state configuration. It's actually an optional query parameter which can be used on every main state. I can fix this by appending ?context to every state configuration, but if i do that and i update my second state in the context query parameter it will also reload my main state, so this isn't feasible. It would be cool if ui-router keeps the unknown query parameters after calling transitionTo. I think this is related to this PR: #115 but i don't know if this will help for my specific use-case. It's also related to this issue: #84

Another thing i tried but didn't work was creating a nested state for every state which has ?context as url ... but then my main state was always triggered and the context parameter was still removed.

I think ui-router should reload the state for query parameters if it's configured in the state configuration. But if the query parameter isn't configured it should still be returned as stateParameter but it shouldn't trigger a reload.

Does anyone have any idea how i can do this? Btw this ticket relates to a previous question i posted about having multiple states: #490

kind regards,
Daan

@pholly
Copy link

pholly commented Nov 1, 2013

I wrote one workaround here: #202

@kbanman
Copy link

kbanman commented Dec 8, 2013

+1

in #202 @pholly presents a [rather ugly] workaround, but someone mentioned a fix was in the works (dynamic parameters). Any word on this?

@xeor
Copy link

xeor commented Dec 31, 2013

Any progress? I'm also waiting for this. Wondering if I should just go for #202 for now..

@timkindberg
Copy link
Contributor

I actually do agree that any arbitrary params should be added to the $stateParams object. Right now that's not on the roadmap though. @nateabele any opposition to this idea? Does it conflict with plans you might have? I'm just thinking maybe we could at least say its a go then if someone wants to do a PR they can at least know it will be accepted.

@nateabele
Copy link
Contributor

Yeah I'm not opposed. I think I can work it into typed parameters for 0.4.

@nateabele
Copy link
Contributor

I'm closing this issue since the features requested have either already been implemented, or are covered by other open issues.

@christopherthielen christopherthielen removed this from the 1.5.0 milestone Nov 16, 2014
@moneytree-doug
Copy link

@nateabele Since its implemented, where is the PR related to this? Its not very clear in the documentation for how I can keep all my query parameters (?limit=1) between states.

@alexander-bobin
Copy link

@nateabele Could you point us to some documentation or info around how optional query params can be persisted?

@moneytree-doug
Copy link

@alexander-bobin What I ended up doing was adding a listener for the $stateChangeStart and then transition to the toState with the fromParams.

For example (CoffeeScript):

persistQueryParams = (event, toState, toParams, fromState, fromParams) ->
      event.preventDefault()
      $state.go(toState.name, fromParams)

$rootScope.$on("$stateChangeStart", persistQueryParams)

@ehorodyski
Copy link

@alexander-bobin Could you show an example of where to add that function?

@nateabele Any place this is documented?

@nateabele
Copy link
Contributor

@ehorodyski It's in a new codebase that will be released shortly. @christopherthielen Isn't parameter-squashing (or non-squashing) in a current release? I don't recall what it touches, but if you point me to the right lines of code, I can bang out some docs.

@christopherthielen
Copy link
Contributor

Parameter squashing is in 0.2.13 for sure, and documented here:
http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider (ctrl-f "squash")

Here's the RFC it came from: #1501

However, I think this discussion may be confusing dynamic params with un-squashed params.

@ehorodyski
Copy link

Thanks @nateabele and @christopherthielen. It was a bit hidden in the docs...at least in my opinion =P

I'll give params: {param1: { array: true }} a shot, but with about 13 different possible parameters it's rough (and I believe one of my colleagues tried looping through and wasn't able to get this working correctly). I found another solution that intercepts the $stateChanging event (or what it's called) and re-adds $location.search() but it's a lot of overhead for one state, right?

Edit: While I'm able to set {array: true}, using the default value {value: [], array: true} is not setting the parameters to empty arrays by default, they stay as undefined.

@benbracha
Copy link

Hey,

Found this thread, and several similar around squash, dynamic and optional parameters.
I'm still not sure how to solve the issue @moneytree-doug or @daanporon raised:

Its not very clear in the documentation for how I can keep all my query parameters (?limit=1) between states.

I'm having a similar requirement:
I want to have a "sticky" query parameter, for example: "?token=someValue"
It should be persist w/e I navigate in my app.
I don't want to re-define it on each state.
Moreover, some states defines their own query params.. In this case - I want their params to be augmented to my "sticky" one (e.g "?token=someValue&otherParam=otherValue").

I saw some workarounds like in here: #202
But I would expect this to be supported somehow..

@nateabele any help?

Thanks

@qrpike
Copy link

qrpike commented Jul 22, 2016

Anyone have a solution to @benbracha 's problem? I am running into the same thing.

@Gash003
Copy link

Gash003 commented Nov 29, 2016

+1
I also can't find solution for problem initially raised by @daanporon and recalled @moneytree-doug and @benbracha
Is there any way to pass optional query parameters between states?

@moneytree-doug
Copy link

moneytree-doug commented Nov 30, 2016

@benbracha @Gash003 @qrpike

So what I did was basically grab the toParams and fromParams and then merged it. If you want all your states to support a query param, you can just add it to every state manually or decorate it with the decorator.

Decorator example,

    $stateProvider.decorator('url', (state, parent) ->
      if state.url.indexOf('?') > -1
        url = "#{state.url}&token"
      else
        url = "#{state.url}?token"
      return $urlMatcherFactoryProvider.compile(url);
    );

Basic example for passing the param to the next state,

persistQueryParams = (event, toState, toParams, fromState, fromParams) ->
      if !toParams.token && fromParams.token
        event.preventDefault()
      	toParams.token = fromParams.token
        $state.go(toState.name, toParams)

$rootScope.$on("$stateChangeStart", persistQueryParams)

To further build on the example for params, you can use angular.extend to help merge params, but you would want to make sure that is tested since it can be erroneous when you have more params in different states.

@Gash003
Copy link

Gash003 commented Nov 30, 2016

Thanks @moneytree-doug for the quick response.
When I tried solution with event listener it ended up with an infinite loop.
Line $state.go(toState.name, toParams) triggers $stateChangeStart event again which in turn invokes persistQueryParams() once again.
I decided to add this param to each state manually, however I feel that it might be a good idea to add support for "sticky" query parameters described by @benbracha.

@moneytree-doug
Copy link

@Gash003 I updated the example to put the state.go into the if block. It's just to illustrate the basic idea, but it should work. I would recommend using the decorator instead of adding the param to each state manually (assuming that you need it have it everywhere).

@noullet
Copy link

noullet commented Dec 16, 2016

@moneytree-doug Your decorator misses logic from the existing stateBuilder for URL. One can keep a reference of the original by calling $stateProvider.decorator('url') and simply call it from the decorator after altering the state URL, thus leaving the implementation details to the original function.

However, this solution doesn't work for me when using nested states: the query parameter, which has been added to every state under the same name thanks to the decorator trick, is thus repeated in the URL for every state in the current tree.

I would really like a "sticky" query parameter and I don't think that any of the tools offered by UI Router answers this need. Any insight from the development team?

In the meantime, I implemented it through painful manual juggling between $location.search() and UI router state change listeners...

@christopherthielen
Copy link
Contributor

@noullet you should be able to "sticky" a query parameter by declaring on a parent state.

  
  $stateProvider.state({
    name: 'parent',
    url: '?query',
    template: '<ui-view></ui-view>'
  })
  
  $stateProvider.state({ 
    name: 'home', 
    parent: 'parent',
    url: '/home', 
    controller: function ($scope, $stateParams) { $scope.query = $stateParams.query },
    template: '<h1>home state loaded</h1> ' +
                 'Param: {{ query }}' +
                 '<div ui-view></div>'
  });
  

http://plnkr.co/edit/0XPeWOxJ1gZXGvXMl90J?p=preview

@noullet
Copy link

noullet commented Dec 16, 2016

@christopherthielen Thanks! I can't believe I didn't think about this solution, it's really time for holidays...

It doesn't work for me yet because my use case is far from being simple, but it's a step forward a more elegant solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests