It is often the case when building applications that you will want to build features that would involve which page the application is currently on. When this is a one-time inspection, it isn't a problem, as both Angular and default browser APIs allow you to easily inspect the current page.
Things get a bit stickier when you want the state of the page to reflect the state of the URL, for example, if you want to visually indicate which link corresponds to the current page. A from-scratch implementation of this would require some sort of state machine that would know when navigation events occur and what and how to modify at each given route.
Fortunately, Angular 2 gives you some excellent tools to do this right out of the box.
The code, links, and a live example of this are all available at .
Begin with the Array and anchor-tag-based implementation shown in the Navigating with routerLinks recipe.
Your goal is to use RouterLinkActive
to introduce some simple stateful route behavior.
RouterLinkActive
allows you to conditionally apply classes when the current route matches the corresponding routerLink
on the same element. Proceed directly to adding it as an attribute directive to each link as well as a matching CSS class:
[app/root.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <a [routerLink]="['']" [routerLinkActive]="'active-navlink'">Default</a> <a [routerLink]="['article']" [routerLinkActive]="'active-navlink'">Article</a> <router-outlet></router-outlet> `, styles: [` .active-navlink { color: red; text-transform: uppercase; } `] }) export class RootComponent {}
This is all you need for links to become active! You will notice that Angular will conditionally apply the active-navlink
class based on the current route.
However, when testing this, you will notice that the /article
route makes both the links appear active. This is due to the fact that by default, Angular marks all routerLinks
that match the current route as active.
This behavior is useful in cases where you may want to show a hierarchy of links as active for example, at route /user/123/detail
, it could make sense that the separate links /user
, /user/123
, and /user/123/detail
are all shown as active.
However, in the case of this recipe, this behavior is not useful to you, and Angular has another router directive, routerLinkActiveOptions
, which binds to an options object. The exact property inside the options object is useful in this case; it controls whether the active state should only be applied in cases of an exact match:
[app/root.component.ts] import {Component} from '@angular/core'; import {Router} from '@angular/router'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <a [routerLink]="['']" [routerLinkActive]="'active-navlink'" [routerLinkActiveOptions]="{exact:true}">Default</a> <a [routerLink]="['article']" [routerLinkActive]="'active-navlink'" [routerLinkActiveOptions]="{exact:true}">Article</a> <router-outlet></router-outlet> `, styles: [` .active-navlink { color: red; text-transform: uppercase; } `] }) export class RootComponent {}
Now you will find that each link will only be active at its respective route.
The routerLinkActive
implementation subscribes to navigation change events that Angular emits from the Router
service. When it sees a NavigationEnd
event, it performs an update of all the attached HTML tags, which includes adding and stripping applicable "active" CSS classes that the element is bound to via the directive.
If you need to bind routerLinkActive
to a dynamic value, the preceding syntax will allow you to do exactly that. For example, you can bind to a
component
member and
modify
it elsewhere, and Angular will handle everything for you. However, if this is not required, Angular will handle routerLinkActive
without the data binding brackets. In this case, the value of the directive no longer needs to be an Angular expression, so you can remove the nested quotes.
The following is behaviorally identical:
[app/root.component.ts] import {Component} from '@angular/core'; import {Router} from '@angular/router'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <a [routerLink]="['']" routerLinkActive="active-navlink" [routerLinkActiveOptions]="{exact:true}"> Default</a> <a [routerLink]="['article']" routerLinkActive="active-navlink" [routerLinkActiveOptions]="{exact:true}"> Article</a> <router-outlet></router-outlet> `, styles: [` .active-navlink { color: red; text-transform: uppercase; } `] }) export class RootComponent {}