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 RouterLink
directive.
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 routerModule.forChild()
method.
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
'message'
. - a variable segment: a string with a
':'
prefix as':folder'
. - 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. UsepathMatch: 'full'
to force a full matching strategy. - a wildcard:
**
matches anything.
The action part can be redirectTo
, 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 /users;name=nate;type=admin/
.
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: popup
and 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.
The routerState
has two properties: snapshot
, and root
. The 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:
|
|
The 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.
4.2 Data
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.