91

I'm creating a tab based page which shows some data. I'm using UI-Router in AngularJs to register states.

My aim is to have one default tab open on page load. Each tab have sub tabs, and I would like to have a default sub tab open when changing tabs.

I was testing with onEnter function and inside I'm using $state.go('mainstate.substate'); but it seems not to work due to loop effect issues (on state.go to substate it calls its parent state and so on, and it turns into a loop).

$stateProvider

.state('main', {
  url: '/main',
  templateUrl: 'main.html',
  onEnter: function($state) {
    $state.go('main.street');
  }
})

.state('main.street', {
  url: '/street',
  templateUrl: 'submenu.html',
  params: {tabName: 'street'}
})

Here I created a plunker demo.

For now everything works, except that I don't have the default tab open and that's exactly what I need.

Thank you for your suggestions, opinions and ideas.

6 Answers 6

173

Update: 1.0 Onwards Supports redirectTo out of the box.

https://ui-router.github.io/ng1/docs/latest/interfaces/state.statedeclaration.html#redirectto


I created an example here.

This solution comes from a nice "Comment" to an an issue with redirection using .when() (https://stackoverflow.com/a/27131114/1679310) and really cool solution for it (by Chris T, but the original post was by yahyaKacem)

https://github.com/angular-ui/ui-router/issues/1584#issuecomment-75137373

So firstly let's extend main with redirection setting:

$stateProvider
    .state('main', {
      url: '/main',
      templateUrl: 'main.html',
      redirectTo: 'main.street',
    })

And add only this few lines into run

app.run(['$rootScope', '$state', function($rootScope, $state) {

    $rootScope.$on('$stateChangeStart', function(evt, to, params) {
      if (to.redirectTo) {
        evt.preventDefault();
        $state.go(to.redirectTo, params, {location: 'replace'})
      }
    });
}]);

This way we can adjust any of our states with its default redirection...Check it here

EDIT: Added option from comment by @Alec to preserve the browser history.

Sign up to request clarification or add additional context in comments.

4 Comments

This seems to clobber the back button.
@Swordfish0321 to fix the back button, make this small change: $state.go(to.redirectTo, params, {location: 'replace'}); This will cause the new state to replace the previous state (ie the one we're being redirected from) in the history. See docs for $state.go: angular-ui.github.io/ui-router/site/#/api/…
Just wanted to add on that this was real close to what I wanted to do, but I wanted the default URL instead of replacing it, this was easily accomplished by changing '$stateChangeStart' to '$stateChangeSuccess'
ui-router 1.0 has built in support for this: ui-router.github.io/guide/ng1/…
21

In fact even if this solution proposed by Radim did exactly the job, I needed to remember every tab's sub tab (state).

So I found another solution which do the same thing but also remembers every tab substate.

I all have to do was to install ui-router-extras and use the deep state redirect feature:

$stateProvider
  .state('main.street', {
     url: '/main/street',
     templateUrl: 'main.html',
     deepStateRedirect: { default: { state: 'main.street.cloud' } },
  });

Thank you!

Comments

13

As of version 1.0 of the ui-router it supports a redirectTo property. For example:

.state('A', {
  redirectTo: 'A.B'
})

Comments

7

Since version 1.0 of ui-router, a default hook has been introduced using IHookRegistry.onBefore() as demonstrated in the example Data Driven Default Substate in http://angular-ui.github.io/ui-router/feature-1.0/interfaces/transition.ihookregistry.html#onbefore

// state declaration
{
  name: 'home',
  template: '<div ui-view/>',
  defaultSubstate: 'home.dashboard'
}

var criteria = {
  to: function(state) {
    return state.defaultSubstate != null;
  }
}
$transitions.onBefore(criteria, function($transition$, $state) {
  return $state.target($transition$.to().defaultSubstate);
});

1 Comment

This sort of work for me, although, I had to tweak it (also using ES6) $transitions.onBefore({ to: state => state.defaultSubstate != null }, trans => trans.router.stateService.target(trans.to().defaultSubstate));
4
app.config(function($stateProvider,$urlRouterProvider){

    $urlRouterProvider.when("/state","/state/sub-state");

    })

3 Comments

Can you provide an explanation as to what this does and why it's better than the already existing answers?
This solution is the easiest and worked well for me.
This is the best answer by far. More concise than using change events. No need to add packages. I don't know how that's not clear to anybody. I don't know how the accepted answer got upvoted so much.
1

If someone comes here for an answer regarding how to implement a simple redirect for a state and, as it happened to me, doesn't have the opportunity to use the new router...

Obviously again if you can, @bblackwo answer is great:

$stateProvider.state('A', {
  redirectTo: 'B',
});

If you can't then just manually redirect it:

$stateProvider.state('A', {
  controller: $state => {
    $state.go('B');
  },
});

I hope it helps!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.