Core state definition and registration functionality for defining application states with views, URLs, parameters, and lifecycle hooks. States form a hierarchical tree structure supporting inheritance and nested routing.
Angular 1.x provider for configuring states during the application configuration phase.
/**
* The Angular 1.x StateProvider for registering and configuring states
*/
interface StateProvider {
/** Register a new state configuration */
state(name: string, definition: Ng1StateDeclaration): StateProvider;
/** Register a state using an object with name property */
state(definition: Ng1StateDeclaration): StateProvider;
/** Decorate state builder functions for custom functionality */
decorator(name: string, func: BuilderFunction): StateProvider;
/** Register invalid state handler */
onInvalid(callback: OnInvalidCallback): Function;
}Usage Examples:
angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function($stateProvider) {
// Basic state registration
$stateProvider.state('home', {
url: '/home',
template: '<h1>Home Page</h1>'
});
// Nested state registration
$stateProvider
.state('users', {
url: '/users',
template: '<ui-view></ui-view>'
})
.state('users.list', {
url: '',
component: 'userList'
})
.state('users.detail', {
url: '/{userId}',
component: 'userDetail'
});
}]);Complete state configuration interface with all Angular 1.x specific properties.
/**
* State declaration object for defining states with Angular 1.x integration
*/
interface Ng1StateDeclaration extends StateDeclaration {
/** State name (optional if provided as first parameter to state()) */
name?: string;
/** URL pattern with parameters */
url?: string;
/** State parameters configuration */
params?: { [key: string]: ParamDeclaration | any };
/** Abstract state flag - cannot be navigated to directly */
abstract?: boolean;
/** Parent state reference */
parent?: string | StateDeclaration;
/** Multiple named views configuration */
views?: { [key: string]: string | Ng1ViewDeclaration };
/** HTML template string or function */
template?: string | Function;
/** Template URL or function returning URL */
templateUrl?: string | Function;
/** Injectable template provider function */
templateProvider?: IInjectable;
/** Controller function or name */
controller?: IInjectable | string;
/** Controller alias for scope */
controllerAs?: string;
/** Injectable controller provider function */
controllerProvider?: IInjectable;
/** Angular 1.5+ component name */
component?: string;
/** Injectable component provider function */
componentProvider?: IInjectable;
/** Component binding mappings from resolve data */
bindings?: { [key: string]: string };
/** Scope variable name for resolve data */
resolveAs?: string;
/** Dependency resolution configuration */
resolve?: { [key: string]: IInjectable };
/** State entry lifecycle hook */
onEnter?: Ng1StateTransitionHook | IInjectable;
/** State exit lifecycle hook */
onExit?: Ng1StateTransitionHook | IInjectable;
/** State retain lifecycle hook */
onRetain?: Ng1StateTransitionHook | IInjectable;
/** Deprecated: Dynamic search parameter behavior */
reloadOnSearch?: boolean;
/** Custom data attached to state */
data?: any;
}Usage Examples:
// Complex state with all features
$stateProvider.state('dashboard', {
url: '/dashboard?tab',
abstract: true,
template: '<div class="dashboard"><ui-view></ui-view></div>',
controller: 'DashboardController',
controllerAs: 'vm',
resolve: {
currentUser: ['AuthService', function(AuthService) {
return AuthService.getCurrentUser();
}],
permissions: ['currentUser', 'PermissionService',
function(currentUser, PermissionService) {
return PermissionService.getUserPermissions(currentUser.id);
}]
},
onEnter: ['$state', 'currentUser', function($state, currentUser) {
if (!currentUser.isActive) {
return $state.go('login');
}
}],
data: {
requiresAuth: true,
title: 'Dashboard'
}
});
// Component-based state
$stateProvider.state('profile', {
url: '/profile/{userId}',
component: 'userProfile',
resolve: {
user: ['$stateParams', 'UserService',
function($stateParams, UserService) {
return UserService.getUser($stateParams.userId);
}]
},
bindings: {
profileData: 'user' // Map resolve 'user' to component binding 'profileData'
}
});
// Multi-view state
$stateProvider.state('app', {
url: '/app',
views: {
'header': {
component: 'appHeader'
},
'sidebar': {
templateUrl: 'sidebar.html',
controller: 'SidebarController'
},
'content': {
template: '<ui-view></ui-view>'
}
}
});Hooks that execute during state transitions for the specific state.
/**
* State transition hook function signature with Angular 1.x dependency injection
*/
interface Ng1StateTransitionHook {
/** State hook function with injectable parameters */
(...injectables: any[]): HookResult;
}
type HookResult = boolean | TargetState | void | Promise<boolean | TargetState | void>;Usage Examples:
$stateProvider.state('secure', {
url: '/secure',
template: '<h1>Secure Area</h1>',
// Check authentication on enter
onEnter: ['$state', 'AuthService', function($state, AuthService) {
if (!AuthService.isAuthenticated()) {
return $state.go('login');
}
}],
// Log state exit
onExit: ['$log', function($log) {
$log.info('Leaving secure area');
}],
// Handle state retention
onRetain: ['$log', function($log) {
$log.info('Staying in secure area');
}]
});
// Async hook with promise
$stateProvider.state('data', {
url: '/data',
template: '<div>Data loaded</div>',
onEnter: ['DataService', function(DataService) {
return DataService.preloadData().then(function(data) {
console.log('Data preloaded:', data);
});
}]
});Configuration for state and URL parameters with validation and transformation.
/**
* Parameter declaration for configuring state parameters
*/
interface ParamDeclaration {
/** Default parameter value */
value?: any;
/** Parameter type name or ParamType instance */
type?: string | ParamType;
/** Array parameter configuration */
array?: boolean | string;
/** URL squashing behavior for default values */
squash?: boolean | string;
/** Dynamic parameter flag for change detection */
dynamic?: boolean;
/** Inherit parameter from parent state */
inherit?: boolean;
/** Disable URL encoding/decoding */
raw?: boolean;
}Usage Examples:
$stateProvider.state('search', {
url: '/search?query&category&page',
params: {
query: {
type: 'string',
value: '',
squash: true // Remove from URL when empty
},
category: {
type: 'string',
value: 'all',
squash: false
},
page: {
type: 'int',
value: 1,
squash: true
},
tags: {
array: true,
value: [],
squash: true
},
config: {
value: { sortBy: 'name' },
type: 'json',
dynamic: true // Changes don't trigger state reload
}
},
template: '<search-results></search-results>'
});Integration with the StateRegistry for dynamic state management.
/**
* StateRegistry extensions for Angular 1.x states
*/
declare module '@uirouter/core/lib/state/stateRegistry' {
interface StateRegistry {
/** Register Angular 1.x state declaration */
register(state: Ng1StateDeclaration | { new (): Ng1StateDeclaration }): StateDeclaration;
}
}Usage Examples:
// Register state dynamically at runtime
angular.module('myApp').run(['$stateRegistry', function($stateRegistry) {
$stateRegistry.register({
name: 'dynamic',
url: '/dynamic',
component: 'dynamicComponent'
});
}]);Common configuration errors and how to avoid them:
// ERROR: Cannot mix state-level view properties with views object
$stateProvider.state('bad', {
template: '<h1>Bad</h1>', // Error: state-level template
views: {
'content': { template: '<div>Content</div>' }
}
});
// CORRECT: Use either state-level OR views object
$stateProvider.state('good1', {
template: '<h1>Good</h1>' // State-level view properties
});
$stateProvider.state('good2', {
views: {
'$default': { template: '<h1>Good</h1>' } // Views object only
}
});
// ERROR: Cannot mix component with template/controller
$stateProvider.state('bad2', {
component: 'myComponent',
template: '<div>Template</div>' // Error: mixing component with template
});
// CORRECT: Use component OR template/controller
$stateProvider.state('good3', {
component: 'myComponent'
});