When routing in any application there comes a point where it makes sense architecturally to share data during navigation. Angular has several tools for sharing data across your apps routing system including Route Guards, Route Resolvers, the Route API and the ActivatedRoute API.
The ActivatedRoute API is an interesting function within Angular as it specifically has to do with the currently activated route in your app and holds a conglomerate of information pertaining to the router.
Let’s dive into the defining the ActivatedRoute
, retrieving it, discovering what data is available and what you can do with it.
the activated route is similar to a path of switches on a motherboard
What is an activated route?
The Angular Docs define the ActivatedRoute as
A service that is provided to each route component that contains route specific information such as route parameters, static data, resolve data, global query params and the global fragment.
With this data we can handle route specific logic, use route specific state and retrieve the route fragments of the current URL.
In a component, we can access this data by injecting the ActivatedRoute API inside the constructor:
import { ActivatedRoute } from '@angular/router' ... constructor(private activatedRoute: ActivatedRoute) {}
What route data is available?
Here is a section from the docs outlining the properties available in the ActivatedRoute
API:
snapshot: ActivatedRouteSnapshot The current snapshot of this route url: Observable<UrlSegment[]> An observable of the URL segments matched by this route. params: Observable<Params> An observable of the matrix parameters scoped to this route. queryParams: Observable<Params> An observable of the query parameters shared by all the routes. fragment: Observable<string> An observable of the URL fragment shared by all the routes. data: Observable<Data> An observable of the static and resolved data of this route. outlet: string The outlet name of the route, a constant. component: Type<any> | string | null The component of the route, a constant. routeConfig: Route | null Read-Only The configuration used to match this route. root: ActivatedRoute Read-Only The root of the router state. parent: ActivatedRoute | null Read-Only The parent of this route in the router state tree. firstChild: ActivatedRoute | null Read-Only The first child of this route in the router state tree. children: ActivatedRoute[] Read-Only The children of this route in the router state tree. pathFromRoot: ActivatedRoute[] Read-Only The path from the root of the router state tree to this route. paramMap: Observable<ParamMap> Read-Only An Observable that contains a map of the required and optional parameters specific to the route. The map supports retrieving single and multiple values from the same parameter. queryParamMap: Observable<ParamMap> Read-Only An Observable that contains a map of the query parameters available to all routes. The map supports retrieving single and multiple values from the query parameter.
The snapshot
property from the ActivatedRoute
contains this ActivatedRouteSnapshot
object:
interface ActivatedRouteSnapshot { routeConfig: Route | null url: UrlSegment[] params: Params queryParams: Params fragment: string data: Data outlet: string component: Type<any> | string | null root: ActivatedRouteSnapshot parent: ActivatedRouteSnapshot | null firstChild: ActivatedRouteSnapshot | null children: ActivatedRouteSnapshot[] pathFromRoot: ActivatedRouteSnapshot[] paramMap: ParamMap queryParamMap: ParamMap toString(): string }
Some properties are duplicated: because they hold the same kind of data but they are not the same types of data. The snapshot properties hold synchronous information that you can access right away; the ActivatedRoute
properties that have the same key names hold observable data which is asynchronous.
Summary of data found in ActivatedRoute
Route Tree and Components
The component
, root
, parent
,firstChild
, children
and pathFromRoot
keys comprise the Route Tree which is made up of ActivatedRouteSnapshots that are being loaded in the route, including the components that are part of the route.
Route State
The Route state lies in the data
property, which is where Resolver and Observable data are kept. Data put into a Route from the resolver or routeGuard is available here.
URL Information
The url
, params
, queryParams
, fragment
, paramMap
and queryParamMap
keys make up the URL information. The url
property only holds the last segment of the URL. For example if your URL path was /home/pangolins
the last segment would be pangolins
. If you want to access the current URL path you would want to get that from the Router API.
Other Route Metadata
More Metadata is stored in the routeConfig
and outlet
properties. The routeConfig
holds a Route
object and the outlet
key stores the name of the router outlet being used.
What is the difference between the ActivatedRoute and ActivatedRouteSnapshot?
The ActivatedRoute is the API that holds observable data that you can use to react to events with. You can subscribe to specific observable properties to get data from it asynchronously. The ActivatedRoute also contains ActivatedRouteSnapshot. The ActivatedRouteSnapshot holds the same activated route data but is a static property.
Static activated route snapshot data
constructor(private activatedRoute: ActivatedRoute) { const activatedRouteSnapshot = activatedRoute.snapshot; }
Observable activated route data
For observable data you must subscribe to a specific observable property on the ActivatedRoute object, for example the data property:
constructor(private activatedRoute: ActivatedRoute) { activatedRoute.data.subscribe((data) => ...) }
What can you do with this knowledge?
Get URL Params
You can get the URL params using the activatedRoutes query param map, along with its built in get method for retrieving the parameters value. (tip: it is possible for parameters to have casing issues; it’s recommended that you normalize keys before getting the value).
// www.briebug.com?favoritepangolin=leroyjenkins ngOnInit() { const params = this._activatedRoute.snapshot.queryParamMap; const favoritePangolin = params.get('favoritepangolin'); }
Get URL Fragment
You may want to get the current URL fragment while the user travels along your page in order to give them a fragment specific user experience. To do that, you can just subscribe to the ActivatedRoute
changes.
listenForRouteFragment(){ this.activatedRoute$.fragment.subscribe((fragment: string) => { if (fragment === 'youGotPaid') { this.makeItRain(); }; }); }
Pass data and retrieve resolver data
Data can be passed during navigation and retrieved in the component within the activated route. You can include data in the route configuration:
const routes: RouterConfig = [ { path: 'pangolins', component: cutePangolinComponent, data: { pangolinArray: [ ... ] } ];
However this approach is not as useful, or as common, as others. You can access this data within the data
property of ActivatedRoute
but the data is static. A dynamic approach would be much more useful, which is where having a resolver comes into play. With a resolver I can fetch my array of Pangolins from the server. (tip: when data is necessary for rendering a view it can be useful to also use a route guard to make sure the data is available before loading the view).
const routes: RouterConfig = [ { path: 'pangolins', component: cutePangolinComponent, resolve: { pangolins: PangolinResolver } ];
Notice how the resolver
is inside the resolve property and not the data
property. When our data resolves, Angular will take care of putting the data requested inside the data
property on the ActivatedRoute
. We can then get our data synchronously or asynchronously inside our component.
constructor(private activatedRoute: ActivatedRoute) { this.pangolins = activatedRoute.snapshot.data['pangolins'] }
Asynchronously may be a good option if there is some logic you want to perform on the data.
listenForPangolins() { this.activatedRoute.data['pangolins'].subscribe((pangolins) => { this.getImagesOfPangolins(pangolins) }) }
Debugging the Router
Logging the router state can be a helpful tool for debugging routes in Angular. The ActivatedRoute
holds all the router state you need to see your current route path and history. This can be useful in creating a more textual or visual representation of what your router state is; especially if your app holds a complex spaghetti of routes.
constructor(private activatedRoute: ActivatedRoute) { // what child routes are being loaded right now? const childRouteSnapshots = activatedRoute.snapshot.children; console.log('children snapshots: ', childRouteSnapshots); // what is the parent of this route? const parentRouteSnapshot = activatedRoute.snapshot.parent; console.log('parent route snapshot: ', parentRouteSnapshot); // what is the full path of my router? const routePath = activatedRoute.snapshot.pathFromRoot; console.log('my path from root: ', routePath); // I have multiple router outlets. Is this using the correct router outlet? const outletName = activatedRoute.snapshot.outlet; console.log('current router outlet name: ', outletName); }
What about using Router?
Great question! The Angular Router API comes with many methods used to control the router as well as some info about the current route. A good rule of thumb is to use the Router API if you need to manipulate the route (redirecting, navigating to another part of the app, etc) or need the current full textual URL path. If you just need information about the route and the router state then you should use the ActivatedRoute API.
I just came here to get the URL Parameters…
Well now you know so much more! The ActivatedRoute is such a large object that it can be cumbersome to work through. Now that you know the basics of what data is located in what properties you will have an easier time finding the information you need about your router. The Activated Route is a great API for getting data from your router, knowing your router’s state and becoming more familiar with how the Angular router functions at its core.