2016-06-23 09:47:54 -07:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2016-06-15 09:01:05 -07:00
|
|
|
import {AfterContentInit, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer} from '@angular/core';
|
|
|
|
import {Subscription} from 'rxjs/Subscription';
|
|
|
|
|
|
|
|
import {NavigationEnd, Router} from '../router';
|
2016-06-28 16:47:13 -07:00
|
|
|
|
|
|
|
import {RouterLink, RouterLinkWithHref} from './router_link';
|
2016-06-15 09:01:05 -07:00
|
|
|
|
|
|
|
|
2016-06-28 14:49:29 -07:00
|
|
|
/**
|
2016-09-12 09:47:44 -07:00
|
|
|
* @whatItDoes Lets you add a CSS class to an element when the link's route becomes active.
|
2016-09-10 16:50:38 -07:00
|
|
|
*
|
|
|
|
* @howToUse
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <a [routerLink]='/user/bob' routerLinkActive='active-link'>Bob</a>
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @description
|
|
|
|
*
|
2016-06-28 14:49:29 -07:00
|
|
|
* The RouterLinkActive directive lets you add a CSS class to an element when the link's route
|
|
|
|
* becomes active.
|
|
|
|
*
|
|
|
|
* Consider the following example:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <a [routerLink]="/user/bob" routerLinkActive="active-link">Bob</a>
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* When the url is either '/user' or '/user/bob', the active-link class will
|
|
|
|
* be added to the `a` tag. If the url changes, the class will be removed.
|
|
|
|
*
|
|
|
|
* You can set more than one class, as follows:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <a [routerLink]="/user/bob" routerLinkActive="class1 class2">Bob</a>
|
2016-09-10 16:50:38 -07:00
|
|
|
* <a [routerLink]="/user/bob" [routerLinkActive]="['class1', 'class2']">Bob</a>
|
2016-06-28 14:49:29 -07:00
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* You can configure RouterLinkActive by passing `exact: true`. This will add the classes
|
|
|
|
* only when the url matches the link exactly.
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <a [routerLink]="/user/bob" routerLinkActive="active-link" [routerLinkActiveOptions]="{exact:
|
|
|
|
* true}">Bob</a>
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Finally, you can apply the RouterLinkActive directive to an ancestor of a RouterLink.
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <div routerLinkActive="active-link" [routerLinkActiveOptions]="{exact: true}">
|
|
|
|
* <a [routerLink]="/user/jim">Jim</a>
|
|
|
|
* <a [routerLink]="/user/bob">Bob</a>
|
|
|
|
* </div>
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This will set the active-link class on the div tag if the url is either '/user/jim' or
|
|
|
|
* '/user/bob'.
|
|
|
|
*
|
2016-09-10 16:50:38 -07:00
|
|
|
* @selector ':not(a)[routerLink]'
|
|
|
|
* @ngModule RouterModule
|
|
|
|
*
|
2016-06-28 14:49:29 -07:00
|
|
|
* @stable
|
|
|
|
*/
|
2016-06-15 09:01:05 -07:00
|
|
|
@Directive({selector: '[routerLinkActive]'})
|
|
|
|
export class RouterLinkActive implements OnChanges, OnDestroy, AfterContentInit {
|
2016-07-22 16:42:05 -07:00
|
|
|
@ContentChildren(RouterLink, {descendants: true}) links: QueryList<RouterLink>;
|
|
|
|
@ContentChildren(RouterLinkWithHref, {descendants: true})
|
|
|
|
linksWithHrefs: QueryList<RouterLinkWithHref>;
|
2016-06-28 16:47:13 -07:00
|
|
|
|
2016-06-15 09:01:05 -07:00
|
|
|
private classes: string[] = [];
|
|
|
|
private subscription: Subscription;
|
|
|
|
|
2016-08-15 00:39:59 -07:00
|
|
|
@Input() routerLinkActiveOptions: {exact: boolean} = {exact: false};
|
2016-06-15 09:01:05 -07:00
|
|
|
|
|
|
|
constructor(private router: Router, private element: ElementRef, private renderer: Renderer) {
|
|
|
|
this.subscription = router.events.subscribe(s => {
|
|
|
|
if (s instanceof NavigationEnd) {
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
ngAfterContentInit(): void {
|
|
|
|
this.links.changes.subscribe(s => this.update());
|
2016-06-28 16:47:13 -07:00
|
|
|
this.linksWithHrefs.changes.subscribe(s => this.update());
|
2016-06-15 09:01:05 -07:00
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Input()
|
|
|
|
set routerLinkActive(data: string[]|string) {
|
|
|
|
if (Array.isArray(data)) {
|
|
|
|
this.classes = <any>data;
|
|
|
|
} else {
|
|
|
|
this.classes = data.split(' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ngOnChanges(changes: {}): any { this.update(); }
|
|
|
|
ngOnDestroy(): any { this.subscription.unsubscribe(); }
|
|
|
|
|
|
|
|
private update(): void {
|
2016-07-20 17:51:21 -07:00
|
|
|
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
|
2016-06-15 09:01:05 -07:00
|
|
|
|
2016-09-30 17:42:54 +01:00
|
|
|
const isActive = this.hasActiveLink();
|
2016-06-28 16:47:13 -07:00
|
|
|
this.classes.forEach(
|
2016-09-30 17:42:54 +01:00
|
|
|
c => this.renderer.setElementClass(this.element.nativeElement, c, isActive));
|
2016-06-28 16:47:13 -07:00
|
|
|
}
|
|
|
|
|
2016-09-30 17:42:54 +01:00
|
|
|
private isLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
|
|
|
|
return (link: RouterLink | RouterLinkWithHref) =>
|
|
|
|
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
|
|
|
|
}
|
|
|
|
|
|
|
|
private hasActiveLink(): boolean {
|
|
|
|
return this.links.some(this.isLinkActive(this.router)) ||
|
|
|
|
this.linksWithHrefs.some(this.isLinkActive(this.router));
|
2016-06-15 09:01:05 -07:00
|
|
|
}
|
|
|
|
}
|