This blog is an attemp to understand the design and implementation of Angular routing.
1 Basic Concepts
The core routing function is to navigate among components and sync a route state with the url. There are two tree structures used in routing: 1) the
Route array of routes forms a configuration tree. 2) a url represents a router state consisting of the current page’s activated routes. A url is represented as a
UrlTree state tree.
There are two ways to navigate from one router state to another one: imperatively by calling
router.navigate and declaratively by using the
An activated route can be associated with a component. There is always an activated route associated with the root component of the application.
There is a global router service responsible for the management of route states and URL. The global router service and main configurations are imported by
routerModule.forRoot() method. Lazy loaded module routers are imported by
The navigation cycle starts with redirecting (if ther is one) and recognizing a new url to a router state. Then guards and resolvers are processed to generate a new router state, views are activated and location is updated. The router sevice emits events during the lifecycle.
The router service also loads lazy modules and merge definted routes with the main configuration.
2 Route Configuration and URL
The navigation tree are defined by an array of router configuration objects, abbreviated as router objects or routes. A route maps a segement of a url to a routable state such as a component, a redirect, etc.
A route has two parts: a path and an optional action.
The path can be one of the following:
- a constant segment: a string such as
- a variable segment: a string with a
- an empty semgent of
'': any path starts and ends with an empty segment. It consumes nothing but can instantiate a component. It inherits matrix parameters of its parent. Use
pathMatch: 'full'to force a full matching strategy.
- a wildcard:
The action part can be
component or empty for a componentless route.
An url is a serialized router state. A router state is represented by a
UrlTree object that, in addition to the
fragement and the
queryParams properties, has a
parent property and a
children property. The children consists of one or more
UrlSegmentGroup, one for each outlet. A
UrlSegmentGroup has an array of
UrlSegment that is a string between two slashes in the url. Each
UrlSegment is to be matched to a
path property in the router configuraiton.
UrlSegment can contain matrix parameters such as
There is one
UrlSegmentGroup for each outlet. The default anounymous outlet is the primary outlet. Secondary outlet are defined within parentheses in a url, such as
(secondary_outlet_name:secondary_path_name). There could be more than one secondary children separated by a ‘//’. For example:
/inbox/33(popup:message/44//help:overview) means the root has two secondary outlets:
help. In the url
/inbox/33/(messages/44//side:help), there is one secondary outlet
side under the
/inbox/33/. Outlets are routed independently of each other.
Angular uses depth-first search to match a url to the configuration tree to create a
RouterState and a state snapshot.
4 Router States
After matching a url to the configuration tree, we have a set of components and other routing data such as url segments, query parameters, router parameters (also called matrix parameters) and the fragment – together called the current router state. The
routerState is a property of the global router service.
routerState has two properties:
snapshot is a tree of
ActivatedRouteSnapshot objects. These are static objects that are used immediately. The
root is a tree of
ActivatedRoute objects. They are dynamic and are observalbe to listen for state changes. A route state can have multiple trees of
ActivatedRoute, one for each outlet.
4.1 The Interfaces
The three interfaces have the following defintion:
ActivatedRoute exposes its values as observables thus changes can be handled. It can be injected to a component’s constructor. Its
snapshot property points to the current
ActivatedRouteSnapshot object that might be changed when the url changes.
You can config a route with a
data property that is a static object that doesn’t change. The
resolve is used for dynamic data. It takes a name and a resovler type that is provided by an injector. The router combines the resolved and static data into a single proeprty.
Unlike query params, router params, and the segment, the data is not serialized in a url.