How to persist optional state parameter on browser back in ui-router?

Pankaj Parkar picture Pankaj Parkar · Jul 21, 2015 · Viewed 9.5k times · Source

I'm having one parent state that has two children's state inside that I'm going to show one state based on the URL.

Out of those two states one is having to parameters like param1 and param2, I have use params option of ui-router inside state definition.

State

$stateProvider.state('tabs.account', {
    url: '/account',
    views: {
        'content@tabs': {
            templateUrl: 'account.html',
            controller: function($scope, $stateParams) {
                //This params are internally used to make ajax and show some data.
                $scope.param1 = $stateParams.param1;
                $scope.param2 = $stateParams.param2;
            },
        }
    },
    params: {
        param1: { value: null }, //this are optional param
        param2: { value: null } //because they are not used in url
    }
});

If you look at my route the params option is not really introduced inside the URL, that's why I'm considering then as optional.

Problem

Look at plunkr, I've shown two tabs Account & Survey,

  1. Click on Survey tab, then add some data in the textarea which are shown.
  2. Click on Go to Account that will pass those textarea values to the other Account tab by doing ui-sref="tabs.account({param1: thing1, param2: thing2})" on the anchor

  3. Now you will see the param1 & param2 values on html which has been assigned to scope from $stateParams

  4. Now again Click on Survey tab, you will land on the survey page.
  5. Just click browser back, you will notice that param value is not getting null.

Problem Plunkr

I believe you got what I wanted to ask, why the optional parameter value has not been store? as they have been a part of state.

I know I can solve this issue by below two solutions.

  • By creating one service that will share data between two views.
  • By adding parameter inside the state URL. like url: '/account/:param1/:param2', (But i wouldn't prefer this)

I already tried angular-ui-routers sticky states but that doesn't seems to work for me. What is the better way to this?

Is there any way by which I can make my use case working, Any ideas would appreciate.

Github Issue Link Here

Answer

Kasper Lewau picture Kasper Lewau · Jul 25, 2015

I would move the params definition to the parent state, so as to share the optional state params between your two child states.

The child states will inherit the $stateParams from your parent, as such there is no real 'workaround' needed.

Simply inject $stateParams as per usual in your child controllers and you will have full access to the params being passed around. If you don't want to utilise the params in a specific child state, simply avoid injecting them.

This works with;

  • Back button
  • Forward button
  • ui-sref (without params (will keep as-is))
  • ui-sref (with params (will overwrite))

$stateProvider
  .state('parent', {
    params: { p1: null, p2: null }
  })
  .state('parent.childOne', {
    url: '/one',
    controller: function ($stateParams) {
      console.log($stateParams); // { p1: null, p2: null }
    }
  })
  .state('parent.childTwo', {
    url: '/two',
    controller: function ($stateParams) {
      console.log($stateParams); // { p1: null, p2: null }
    }
  })

If you at any point want to clear the params while travelling within the state tree of parent, you would have to do so manually.

That would be the only real caveat I can see by using this solution.

I realise manual clearing may not be desirable in the case you present, but you haven't taken an active stand against it, as such I feel the suggestion has merit.

updated plunker