UI-Router Features
States
UI-Router provides state based routing. Each feature of an application is defined as a state. One state is active at any time, and UI-Router manages the transitions between the states.
Each state describes the URL, the UI (a view or views), data prerequisites, and other logical prerequisites (such as authentication) for a feature. Before activating a state, UI-Router first fetches any prerequisites (asynchronously), and then activates the view(s) and updates the URL.
UI-Router states are hierarchical; states can be nested inside other states, forming a tree.
Child states may inherit data and behavior (such as authentication) from their parent states.
Read more about UI-Router states
Views
A state defines a feature’s UI (and UI behavior) using a view (or multiple views).
A view is a UI component, which is placed into a viewport (<ui-view>
) when the state is activated.
Views can be nested inside other views.
A parent state’s view can create a viewport (<ui-view>
), and an nested state can fill that viewport with their own view when activated.
Each state can have multiple named views, allowing complex layouts. A named view can target an arbitrary viewport, anywhere in the DOM (even outside the component hierarchy of the parent state). This can be used to fill (or override) named viewports such as footers, or nagivation, when some nested state is active.
Read more about UI-Router views
Urls
A state can define a URL, but it isn’t required. If a state has defined a URL, the browser’s location is updated to that URL when the state is active.
A state’s URL is actually a URL fragment. Each state defines only the fragment (portion) of the URL that it “owns”. That fragment is appended to the parent state’s url in the browser URL when the nested state is active.
Parameters
A state can be parameterized.
When a state needs specific data, such as which contact to edit, a parameter such as contactId
may be defined.
The parameter value can be encoded into the browser URL, e.g., url: 'http://myapp.com/edit/1234'
where 1234 is the contactId
.
Parameters can be defined in three locations:
- **Path**: in the URL's path: `/foo/{fooId}` matches '123' in `http://mysite.com/foo/123`
- **Query**: in the URL's query string: `/foo?fooId` matches '123' in `http://mysite.com/foo?fooId=123`
- **Non-url**: arbitrary parameter data may be passed programmatically, and not reflect in the URL
A parameter can be required or optional.
When a state defines a default parameter value, that parameter is optional.
When the parameter value is missing from the URL (for instance), the default parameter value will be used (instead of undefined, or empty string).
This can be useful to define defaults such as folderId: 'inbox'
.
Default parameter values can be “squashed” from the URL.
When the current parameter value is the default value, the URL can either contain the default value, or omit it entirely using a “squash” policy.
For instance, if the folderId
parameter value is the default value of inbox
, the URL can either reflect /mail/inbox
or simply be /mail
.
Parameters can be typed. Typed parameters are encoded as strings in the URL, but are converted to a native type when retrieved in javascript code.
There are a few built in parameter types: string
, int
, bool
, date
, json
.
In addition, custom parameter types may be defined by the user with any encoding/decoding logic that is required.
Resolve Data
A feature often requires that some data be fetched from a server-side API. Often, that data is represented as an ID in a url parameter.
The resolve
mechanism allows data retrieval to be a first class participant in the transition.
When a state is being entered, its resolve data is fetched.
If any of the resolve promises are rejected (perhaps due to a 401, 404, or 500 server response from a REST API),
then the transition’s promise is rejected and the error hooks are invoked.
This enables robust error handling for applications, and helps to avoid leaving the application in an inconsistent state.
Resolve data is declarative. A state defines what data should be fetched (generally by delegating to a service).
A resolve may depend on some other resolve’s result (within the same state, or from any ancestor state).
The resolve process is asynchronous. If a resolve returns a Promise, the transition is suspended until the promise is settled. Because of this, the resolve data participates in the transition lifecycle.
Resolve data is made available to the views, as well as transition hooks.
The resolve system is effectively an asynchronous, hierarchical dependency injection system.
Transitions
Navigating between parts of the application occurs by transitioning from one state to another. Transitions between states are transaction-like, i.e., they either completely succeed or completely fail.
- Lifecycle: transitions have a well defined lifecycle
- before: before the asyc portion of a transition has begun
- start: the transition has begun
- exit: the transition is exiting states
- retain: states are retained (a state was active, and is neither being exited nor entered)
- enter: the transition is entering states
- finish: the transition is finishing
- success/error: after the transition is complete
- Transition Lifecycle Hooks:
- Hooks may be registered for any stage of the transition lifecycle.
- Hooks can alter the transition:
- pause the transition, waiting on some promise
- cancel the transition
- redirect the transition to a new target state
- match criteria:
- A hook can choose which transitions it should be applied to.
- to/from: only run the hook if the transition is going to or coming from a specific state
- entering/exiting: only run the hook if the transition is going to enter or exit a specific state
- criteria types:
- state name: the hook’s match criteria can be state names, such as
banking.account
- glob: the criteria can be a state glob pattern, such ash
banking.**
- callback: the criteria can be a callback function, such as
tostate => tostate.data.requiresAuth == true
- state name: the hook’s match criteria can be state names, such as