Angular Js Ui-router How To Redirect To A Child State From A Parent?
Solution 1:
1) Why is the parent state being reinitialized when .go is called on a child state?
While a transition is in process, any $state.go/transitionTo will cause the currently in process transition to be Superseded. An in-process transition that is superseded is cancelled immediately. Since your original transition to inventory
is not completed by the time all the states' onEnters are called, the original transition is cancelled and a new transition to inventory.low
is started from the previously active state.
See ui-router src https://github.com/angular-ui/ui-router/blob/master/src/state.js#L897 ...
2) How then, would you handle redirecting to a child state?
You could...
- Wrap
$state.go
in a$timeout()
to allow the original transition to complete before redirecting. - Call $state.go from your controller instead. UI-router invokes the controller from the ui-view directive AFTER the transition is completed.
In any case, be very sure you want your app to redirect like this. If a user navigated directly to any other child state of inventory (such as inventory.high
), the redirect will still occur, forcing them to inventory.low
which would not be what they intended.
Solution 2:
I had the same problem. The simple solution I found is to listen state changes and redirect to your child state from there.
It's kind of hack that makes routes redirecting to child states by default. It's not needed to dourl: ''
or $state.go()
, they don't work correctly.
So, in config
file:
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
if (toState.redirectTo) {
event.preventDefault();
$state.go(toState.redirectTo, toParams);
}
});
In state
file:
.state('home', {
url: '',
redirectTo: 'home.list'
});
I've made an example on gist: https://gist.github.com/nikoloza/4ab3a94a3c6511bb1dac
Solution 3:
You need to step back and think about what you're trying to achieve. What's the point of having a state when all it's doing is redirecting to a child state?
Regarding your first question, parent states are always activated when you arrive at a child state, this behaviour is extremely useful in sharing data among states, and without it nested routing would be impossible (or rather wouldn't make sense).
As for the 2nd question, I've worked on a few big angular apps and so far I haven't found myself needing to do that.
OK, believe it or not, as much I'd hate to say it, right now I came across a scenario where I needed to do this. I have a profile/userName
route (technically this should be profile/userName/details
) and a profile/userName/products
route, I wanted to have a master view for both states but at the same time I wanted the profile/userName
route have a clean url, like: profile/mike62
, NOT profile/mike62/details
. So I ended up doing this:
.state('publicProfile', { url: '/profile/{username}'})//this is the base/shell state
.state('publicProfile.details',{url:null})//I want this to be my de-facto state, with a clean URL, hence the null url
.state('publicProfile.products', {url:'/products/{exceptProductId:/?.*}'})
Ended up achieving it like this, there are many ways though:
in my publicProfile
state controller (this is the base state):
$scope.state = $state;
$scope.$watch('state.current', function(v) {
if(v.name=='publicProfile') {//want to navigate to the 'preferred' state if not going to publicProfile.products$state.go('publicProfile.details');
};
}, true);
Yes, it does feel hacky but now I know that there are some edge cases where we want to do this, althopugh we could rethink our state design altogether. Another, dirtier way would be to check the current state in a $timeout with a small delay inside the base state, if we are not on the publicProfile.products
state, we navigate to our preferred/de-facto state of publicProfile.details
.
Solution 4:
It looks like you're trying to set a default child state.
That's a commonly asked question about ui-router: How to: Set up a default/index child state
The tl;dr is to use abstract states by settings abstract: true
in the parent state. If you add multiple child states, it'll default to first child state.
$stateProvider
.state('inventory', {
abstract: true,
url: '/inventory',
templateUrl: 'views/inventory.html',
controller: 'InventoryCtrl'
}).
.state('inventory.low', {
url: '/low',
templateUrl: 'views/inventory-table.html',
controller: 'LowInventoryCtrl'
});
Solution 5:
Per pdvorchik's answer on the related GitHub thread, there is a simple fix for this which worked perfectly for me, consisting of wrapping the $state.go
call in a .finally()
call to make sure the first transition completes before a new one is started.
onEnter: ['$state', function($state){
if ($state.transition) {
$state.transition.finally(function() {
$state.go('home.my.other.state', {})
});
}
}]
Post a Comment for "Angular Js Ui-router How To Redirect To A Child State From A Parent?"