Parameter type system and configuration for URL parameters and state parameters with validation, transformation, and encoding. UI-Router provides a comprehensive parameter system with built-in types and extensibility for custom parameter handling.
Configure state and URL parameters with validation, default values, and behavior options.
/**
* 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:
// Basic parameter configuration
$stateProvider.state('users', {
url: '/users?page&sort&filter',
params: {
page: {
type: 'int',
value: 1,
squash: true // Remove from URL when default value
},
sort: {
type: 'string',
value: 'name',
squash: false // Always show in URL
},
filter: {
type: 'string',
value: '',
squash: true
}
}
});
// Advanced parameter configuration
$stateProvider.state('search', {
url: '/search/{query}?category&tags&options',
params: {
query: {
type: 'string',
value: null // Required parameter
},
category: {
type: 'string',
value: 'all',
squash: true
},
tags: {
array: true, // Accept multiple values
value: [],
squash: true
},
options: {
type: 'json', // JSON serialized object
value: { limit: 10, offset: 0 },
dynamic: true, // Changes don't trigger state reload
squash: true
}
}
});Predefined parameter types for common data formats and URL encoding needs.
/**
* Built-in parameter types with automatic encoding/decoding
*/
type BuiltInParamTypes =
| 'string' // Default string type
| 'int' // Integer numbers
| 'bool' // Boolean values (1/0, true/false)
| 'date' // Date objects (ISO 8601 format)
| 'json' // JSON serialized objects
| 'path' // Path parameters (no forward slashes)
| 'query' // Query/search parameters
| 'hash' // Hash parameters
| 'any'; // No encoding/decodingUsage Examples:
// String parameters (default)
$stateProvider.state('profile', {
url: '/profile/{username:string}', // Explicit string type
// username will be URL-decoded string
});
// Integer parameters
$stateProvider.state('product', {
url: '/product/{id:int}',
// id will be parsed as integer, invalid values rejected
});
// Boolean parameters
$stateProvider.state('settings', {
url: '/settings?debug&verbose',
params: {
debug: { type: 'bool', value: false }, // ?debug=1 or ?debug=true
verbose: { type: 'bool', value: false } // ?verbose=0 or ?verbose=false
}
});
// Date parameters
$stateProvider.state('calendar', {
url: '/calendar/{date:date}',
// date will be parsed as Date object from ISO string
});
// JSON parameters for complex data
$stateProvider.state('report', {
url: '/report?config',
params: {
config: {
type: 'json',
value: { format: 'pdf', includeCharts: true }
// URL: ?config=%7B%22format%22%3A%22pdf%22%7D
}
}
});
// Path parameters (no slashes)
$stateProvider.state('file', {
url: '/file/{filename:path}',
// filename cannot contain forward slashes
});
// Any type (no processing)
$stateProvider.state('raw', {
url: '/raw/{data:any}',
// data passed through without encoding/decoding
});Define custom parameter types for specialized data handling and validation.
/**
* Custom parameter type definition
*/
interface ParamType {
/** Encode parameter value for URL */
encode(val: any): string;
/** Decode parameter value from URL */
decode(val: string): any;
/** Check if value is valid for this type */
is(val: any): boolean;
/** Regular expression pattern for URL matching */
pattern: RegExp;
/** Check if two values are equal (optional) */
equals?(a: any, b: any): boolean;
}
interface ParamTypeDefinition {
encode?: (val: any) => string;
decode?: (val: string) => any;
is?: (val: any) => boolean;
pattern?: RegExp;
equals?: (a: any, b: any) => boolean;
}Usage Examples:
// Custom slug parameter type
angular.module('myApp').config(['$urlServiceProvider', function($urlServiceProvider) {
$urlServiceProvider.config.type('slug', {
encode: function(val) {
return val ? val.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '') : '';
},
decode: function(val) {
return val ? val.replace(/-/g, ' ') : '';
},
is: function(val) {
return typeof val === 'string' && /^[a-z0-9-]+$/.test(val);
},
pattern: /[a-z0-9-]+/
});
// Custom email parameter type
$urlServiceProvider.config.type('email', {
encode: function(val) {
return val || '';
},
decode: function(val) {
return val;
},
is: function(val) {
return typeof val === 'string' &&
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
},
pattern: /[^@\s]+@[^@\s]+\.[^@\s]+/
});
// Custom coordinate parameter type
$urlServiceProvider.config.type('coords', {
encode: function(coords) {
if (!coords || !coords.lat || !coords.lng) return '';
return coords.lat + ',' + coords.lng;
},
decode: function(val) {
if (!val) return null;
const parts = val.split(',');
return {
lat: parseFloat(parts[0]),
lng: parseFloat(parts[1])
};
},
is: function(val) {
return val && typeof val.lat === 'number' && typeof val.lng === 'number';
},
pattern: /-?\d+\.?\d*,-?\d+\.?\d*/,
equals: function(a, b) {
return a && b && a.lat === b.lat && a.lng === b.lng;
}
});
}]);
// Use custom parameter types
$stateProvider.state('article', {
url: '/article/{slug:slug}',
// slug will be encoded/decoded with custom logic
});
$stateProvider.state('contact', {
url: '/contact/{email:email}',
// email will be validated against email pattern
});
$stateProvider.state('map', {
url: '/map/{center:coords}',
// center will be encoded as "lat,lng" and decoded as {lat, lng}
});Handle multiple values for a single parameter using array configuration.
/**
* Array parameter configuration
*/
interface ArrayParamConfig {
/** Enable array mode */
array?: boolean | string;
/** Default array value */
value?: any[];
/** Array squashing behavior */
squash?: boolean;
}Usage Examples:
// Basic array parameters
$stateProvider.state('search', {
url: '/search?tags&categories',
params: {
tags: {
array: true,
value: [],
squash: true
},
categories: {
array: true,
value: ['all'],
squash: false
}
}
});
// URLs with array parameters:
// /search?tags=javascript&tags=angular&tags=routing
// /search?tags[]=javascript&tags[]=angular (alternative syntax)
// /search?categories=tech&categories=tutorial
// Array with custom separator
$stateProvider.state('filter', {
url: '/filter?ids',
params: {
ids: {
array: ',', // Use comma separator instead of repeated params
value: [],
type: 'int' // Array of integers
}
}
});
// URL: /filter?ids=1,2,3,4
// Navigate with array parameters
$state.go('search', {
tags: ['javascript', 'angular', 'ui-router'],
categories: ['tutorial', 'documentation']
});Configure parameter inheritance between parent and child states.
/**
* Parameter inheritance configuration
*/
interface ParameterInheritance {
/** Inherit parameter from parent state */
inherit?: boolean;
}Usage Examples:
// Parent state with shared parameters
$stateProvider.state('app', {
url: '/app?theme&lang',
params: {
theme: { value: 'light', squash: true },
lang: { value: 'en', squash: true }
}
});
// Child state inheriting parent parameters
$stateProvider.state('app.dashboard', {
url: '/dashboard?view',
params: {
theme: { inherit: true }, // Inherit from parent
lang: { inherit: true }, // Inherit from parent
view: { value: 'grid', squash: true }
}
});
// Navigate to child state with inherited parameters
$state.go('app.dashboard', { theme: 'dark', view: 'list' });
// URL: /app/dashboard?theme=dark&view=list&lang=enConfigure parameters that don't trigger state reloads when changed.
/**
* Dynamic parameter configuration for real-time updates
*/
interface DynamicParamConfig {
/** Mark parameter as dynamic (no reload on change) */
dynamic?: boolean;
}Usage Examples:
// Dynamic parameters for real-time updates
$stateProvider.state('chat', {
url: '/chat/{roomId}?scroll&filter',
params: {
roomId: {
type: 'string'
// Static parameter - changing triggers reload
},
scroll: {
type: 'int',
value: 0,
dynamic: true, // Changing doesn't trigger reload
squash: true
},
filter: {
type: 'string',
value: '',
dynamic: true, // Changing doesn't trigger reload
squash: true
}
},
controller: ['$scope', '$stateParams', function($scope, $stateParams) {
// Watch for dynamic parameter changes
$scope.$watch(function() {
return $stateParams.scroll;
}, function(newScroll) {
scrollToPosition(newScroll);
});
$scope.$watch(function() {
return $stateParams.filter;
}, function(newFilter) {
filterMessages(newFilter);
});
}]
});
// Update dynamic parameters without reload
$state.go('.', { scroll: 100 }, { notify: false });
$state.go('.', { filter: 'important' }, { notify: false });Control URL generation behavior for default parameter values.
/**
* Parameter squashing configuration
*/
interface ParameterSquashing {
/** Squash behavior for default values */
squash?: boolean | string;
}Usage Examples:
$stateProvider.state('products', {
url: '/products?page&sort&category',
params: {
page: {
type: 'int',
value: 1,
squash: true // Remove from URL when value is 1
},
sort: {
type: 'string',
value: 'name',
squash: false // Always show in URL
},
category: {
type: 'string',
value: 'all',
squash: '~' // Replace with '~' when default
}
}
});
// Navigation examples:
$state.go('products'); // /products?sort=name&category=~
$state.go('products', { page: 1 }); // /products?sort=name&category=~
$state.go('products', { page: 2 }); // /products?page=2&sort=name&category=~
$state.go('products', { category: 'electronics' }); // /products?sort=name&category=electronicsValidate parameters during navigation and handle validation errors.
/**
* Parameter validation patterns
*/
interface ParameterValidation {
/** URL pattern for parameter matching */
pattern?: RegExp;
/** Type validation function */
is?: (val: any) => boolean;
}Usage Examples:
// Parameter validation with regex patterns
$stateProvider.state('user', {
url: '/user/{id:[0-9]+}', // Only numeric IDs allowed
resolve: {
user: ['$stateParams', 'UserService', function($stateParams, UserService) {
const userId = parseInt($stateParams.id);
if (!userId || userId < 1) {
throw new Error('Invalid user ID');
}
return UserService.getUser(userId);
}]
}
});
// Custom parameter validation
angular.module('myApp').config(['$urlServiceProvider', function($urlServiceProvider) {
$urlServiceProvider.config.type('uuid', {
pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
is: function(val) {
return typeof val === 'string' && this.pattern.test(val);
}
});
}]);
$stateProvider.state('document', {
url: '/document/{id:uuid}',
// id must be valid UUID format
});
// Handle parameter validation errors
$transitions.onError({}, function(trans) {
const error = trans.error();
if (error.type === 'INVALID_PARAMS') {
console.error('Invalid parameters:', error.detail);
return trans.router.stateService.go('error.params');
}
});Common patterns for accessing and using parameters in components and controllers.
// Parameter injection in controllers
angular.module('myApp').controller('ProductController',
['$stateParams', '$state', function($stateParams, $state) {
// Access current parameters
this.productId = $stateParams.id;
this.category = $stateParams.category;
this.page = parseInt($stateParams.page) || 1;
// Navigate with parameter changes
this.changePage = function(newPage) {
$state.go('.', { page: newPage });
};
// Navigate with parameter inheritance
this.editProduct = function() {
$state.go('products.edit', {}, { inherit: true });
};
}]);// Component with parameter bindings
angular.module('myApp').component('userProfile', {
bindings: {
userId: '<',
tab: '<'
},
controller: function() {
this.$onChanges = function(changes) {
if (changes.userId) {
this.loadUser(this.userId);
}
if (changes.tab) {
this.switchTab(this.tab);
}
};
}
});
// State with component parameter mapping
$stateProvider.state('profile', {
url: '/profile/{userId}?tab',
component: 'userProfile',
bindings: {
userId: '$stateParams.userId',
tab: '$stateParams.tab'
}
});Common parameter-related errors and solutions:
// Handle missing required parameters
$stateProvider.state('requiresId', {
url: '/item/{id}',
resolve: {
item: ['$stateParams', function($stateParams) {
if (!$stateParams.id) {
throw new Error('Item ID is required');
}
return ItemService.getItem($stateParams.id);
}]
}
});
// Handle invalid parameter types
$transitions.onBefore({}, function(trans) {
const params = trans.params();
// Validate numeric parameters
if (params.id && isNaN(parseInt(params.id))) {
console.error('Invalid ID parameter:', params.id);
return trans.router.stateService.go('error.invalid');
}
// Validate array parameters
if (params.tags && !Array.isArray(params.tags)) {
params.tags = [params.tags]; // Convert single value to array
return trans.router.stateService.go(trans.to(), params, { replace: true });
}
});