Closed
Description
The issue only occurs during a state transition when the ancestor's resolves have loaded, but resolves in between that ancestor and the destination state have not.
The code below demonstrates the issue with three states (root, child, grandchild). Navigating from root to .child.grandchild results in an Unknown Provider error as grandchild attempts to inject a resolved value from root into its own resolve.
However, the grandchild state works just fine if navigated to from root.child or directly via url on a fresh page load.
Additionally, removing the (unused in this example) resolve from the root.child state makes the root -> .child.grandchild transition possible.
<!DOCTYPE html>
<html ng-app="ui-router-test">
<head>
</head>
<body>
<p>Issue: Can't go from root to root.child.grandchild</p>
<div ui-view></div>
<textarea rows="4" cols="100">{{error}}</textarea>
<br>
<a target="_blank" href="#/child/grandchild">Link to grandchild</a> (State loads fine fresh in a new window)
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="angular-ui-router.js"></script>
<script type="text/javascript">
angular.module('ui-router-test', ['ui.router']).
config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
$stateProvider.
state('root', {
url: '/',
template: 'Root<br> <button ng-click="gotograndchild()">$state.go(\'.child.grandchild\')</button> (doesn\'t work)<br><button ng-click="gotochild()">$state.go(\'.child\')</button> (works) <div ui-view></div>',
controller: ['$scope', '$state', function($scope, $state){
$scope.gotograndchild = function(){
$state.go('.child.grandchild');
};
$scope.gotochild = function(){
$state.go('.child');
};
}],
resolve: {
root_value: [function(){
return 'Root Value';
}]
}
}).
state('root.child', {
url: 'child',
template: 'Child<br> <button ng-click="gotograndchild()">$state.go(\'.grandchild\')</button> (works)<div ui-view class="root.child"></div>',
controller: ['$scope', '$state', function($scope, $state){
$scope.gotograndchild = function(){
$state.go('.grandchild');
};
}],
resolve: {
// The presence of this resolve breaks the relative transition from root to .child.grandchild
// root.child.grandchild loads fine if directly requested on a fresh page load, or if navigated to from root.child
child_value: [function(){
return 'Child Value';
}]
}
}).
state('root.child.grandchild', {
url: '/grandchild',
template: 'grandchild',
resolve: {
// the issue appears to be that root_value, when already resolved on root, is not available
// during the relative transition from root to .child.grandchild when root.child's child_value is being resolved.
grandchild_value: ['root_value', function(root_value){
return root_value + ' : Grandchild';
}]
}
});
$urlRouterProvider.otherwise('/');
}]).run(['$state', '$rootScope', function($state, $rootScope){
$rootScope.$on('$stateChangeError', function(event, to, toParams, from, fromParams, error){
$rootScope.error = error.message;
});
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams){
$rootScope.error = '';
});
}]);
</script>
</body>
</html>