Here is what i have so far with ui-router states:
$stateProvider
.state('tools', {
url: '/tools/:tool',
template: '<div ui-view=""></div>',
abstract: true,
onEnter: function ($stateParams, $state, TOOL_TYPES) {
if (TOOL_TYPES.indexOf($stateParams.tool) === -1) {
$state.go('error');
}
}
})
.state('tools.list', {
url: '',
templateUrl: 'app/tools/tools.tpl.html',
controller: 'ToolsController'
})
.state('tools.view', {
url: '/:id/view',
templateUrl: 'app/tools/partials/tool.tpl.html',
controller: 'ToolController'
});
As you can see parent state has parameter tool
which can be only in TOOL_TYPES
array. So in case when tool
is not available, i want to redirect to the error page.
Actually, everything works as expected, but i get two errors:
TypeError: Cannot read property '@' of null
TypeError: Cannot read property '@tools' of null
So i guess, child states have been 'hit' anyway. Is it possible to prevent this? Or maybe there is some other way to achieve what i want?
Angular ui-router's documentation mentions that onEnter
callbacks gets called when a state becomes active, hence, the child states were activated.
To solve this problem you need to implement two things:
Create a resolve
that returns a rejected promise once a specific condition does not apply to that state. Make sure that the rejected promise is passed with information regarding the state to redirect to.
Create a $stateChangeError
event handler in the $rootScope
and use the 6th parameter which is the representation of the information you have passed in the rejected promise. Use the information to create your redirect implementation.
DEMO
Javascript
angular.module('app', ['ui.router'])
.value('TOOL_TYPES', [
'tool1', 'tool2', 'tool3'
])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('error', {
url: '/error',
template: 'Error!'
})
.state('tools', {
url: '/tools/:tool',
abstract: true,
template: '<ui-view></ui-view>',
resolve: {
tool_type: function($state, $q, $stateParams, TOOL_TYPES) {
var index = TOOL_TYPES.indexOf($stateParams.tool);
if(index === -1) {
return $q.reject({
state: 'error'
});
}
return TOOL_TYPES[index];
}
}
})
.state('tools.list', {
url: '',
template: 'List of Tools',
controller: 'ToolsController'
})
.state('tools.view', {
url: '/:id/view',
template: 'Tool View',
controller: 'ToolController'
});
})
.run(function($rootScope, $state) {
$rootScope.$on('$stateChangeError', function(
event, toState, toStateParams,
fromState, fromStateParams, error) {
if(error && error.state) {
$state.go(error.state, error.params, error.options);
}
});
})
.controller('ToolsController', function() {})
.controller('ToolController', function() {});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With