-
Notifications
You must be signed in to change notification settings - Fork 3k
Nested States & Nested Views
◄ Back (State Manager)
Next (Multiple Named Views) ►
States can be nested within each other. You can specify nesting in several ways:
You can use dot syntax to infer your hierarchy to the $stateProvider. Below, contacts.list
becomes a child of contacts
.
$stateProvider
.state('contacts', {})
.state('contacts.list', {});
Alternately, you can specify the parent of a state via the parent
property.
$stateProvider
.state('contacts', {})
.state('list', {
parent: 'contacts'
});
If you aren't fond of using string-based states, you can also use object-based states. The name
property goes in the object and the parent
property must be set on all child states, like this:
var contacts = {
name: 'contacts', //mandatory
templateUrl: 'contacts.html'
}
var contactsList = {
name: 'list', //mandatory
parent: contacts, //mandatory
templateUrl: 'contacts.list.html'
}
$stateProvider
.state(contacts)
.state(contactsList)
You can usually reference the object directly when using other methods and property comparisons:
$state.transitionTo(states.contacts);
$state.self === states.contacts;
$state.includes(states.contacts)
You can attach custom data to the state object (we recommend using a data
property to avoid conflicts).
// Example shows an object-based state and a string-based state
var contacts = {
name: 'contacts',
templateUrl: 'contacts.html',
data: {
customData1: 5,
customData2: "blue"
}
}
$stateProvider
.state(contacts)
.state('contacts.list', {
templateUrl: 'contacts.list.html',
data: {
customData1: 44,
customData2: "red"
}
})
With the above example states you could access the data like this:
function Ctrl($state){
console.log($state.current.data.customData1) // outputs 5;
console.log($state.current.data.customData2) // outputs "blue";
}
Child states will load their templates into their parent's ui-view
.
$stateProvider
.state('contacts', {
templateUrl: 'contacts.html',
controller: function($scope){
$scope.contacts = [{ name: 'Alice' }, { name: 'Bob' }];
}
})
.state('contacts.list', {
templateUrl: 'contacts.list.html'
});
function MainCtrl($state){
$state.transitionTo('contacts.list');
}
<!-- index.html -->
<body ng-controller="MainCtrl">
<div ui-view></div>
</body>
<!-- contacts.html -->
<h1>My Contacts</h1>
<div ui-view></div>
<!-- contacts.list.html -->
<ul>
<li ng-repeat="contact in contacts">
<a>{{contact.name}}</a>
</li>
</ul>
When the application is in a particular State (aka when a state is "active"), all its ancestor states are implicitly active as well. In the sample, when "contacts.list" state is active, the "contacts" state is implicitly active as well. Child states inherit views (templates/controllers) and resolved dependencies from parent state(s), which they can override.
Here contacts.list
and contacts.detail
are both inheriting the controller from contacts
:
$stateProvider
.state('contacts', {
template: '<h1>My Contacts</h1>',
controller: function($scope){
$scope.contacts = [{ name: "Alice", favpet: "Mouse" },
{ name: "Bob", favpet: "Python" }];
}
})
.state('contacts.list', {
template: '<ul><li ng-repeat="contact in contacts">' +
'<a ui-state-ref="contacts.detail">{{contact.name}}</a>' +
'</li></ul>'
})
.state('contacts.detail', {
template: "{{contact.name}}'s favorite pet is {{contact.favpet}}"
});
An abstract state can have child states but can not get activated itself. An 'abstract' state is simply a state that can't be transitioned to, because it's only there to provide inherited properties that are common to its child states.
Here is an example where the 'contacts' state is abstract. Its main purpose is to provide its child states with access to the $scope.contacts data. $scope.contacts will be available to both child state views for interpolation.
$stateProvider
.state('contacts', {
abstract: true,
controller: function($scope){
$scope.contacts = [{ name: "Alice" }, { name: "Bob" }];
})
.state('contacts.list', {
templateUrl: 'contacts.list.html'
// inherits controller from parent state
})
.state('contacts.detail', {
templateUrl: 'contacts.detail.html'
// inherits controller from parent state
})