Skip to content

Commit f78b8e8

Browse files
committed
created routerLinkActive directive for nativescript
1 parent 930e0a2 commit f78b8e8

File tree

3 files changed

+140
-25
lines changed

3 files changed

+140
-25
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {AfterContentInit, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer} from '@angular/core';
2+
import {Subscription} from 'rxjs/Subscription';
3+
4+
import {NavigationEnd, Router} from '@angular/router/router';
5+
import {UrlTree, containsTree} from '@angular/router/url_tree';
6+
7+
import {NSRouterLink} from './ns-router-link';
8+
9+
10+
/**
11+
* The NSRouterLinkActive directive lets you add a CSS class to an element when the link's route
12+
* becomes active.
13+
*
14+
* Consider the following example:
15+
*
16+
* ```
17+
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="active-link">Bob</a>
18+
* ```
19+
*
20+
* When the url is either '/user' or '/user/bob', the active-link class will
21+
* be added to the component. If the url changes, the class will be removed.
22+
*
23+
* You can set more than one class, as follows:
24+
*
25+
* ```
26+
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="class1 class2">Bob</a>
27+
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="['class1', 'class2']">Bob</a>
28+
* ```
29+
*
30+
* You can configure NSRouterLinkActive by passing `exact: true`. This will add the classes
31+
* only when the url matches the link exactly.
32+
*
33+
* ```
34+
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="active-link" [nsRouterLinkActiveOptions]="{exact:
35+
* true}">Bob</a>
36+
* ```
37+
*
38+
* Finally, you can apply the NSRouterLinkActive directive to an ancestor of a RouterLink.
39+
*
40+
* ```
41+
* <div [nsRouterLinkActive]="active-link" [nsRouterLinkActiveOptions]="{exact: true}">
42+
* <a [nsRouterLink]="/user/jim">Jim</a>
43+
* <a [nsRouterLink]="/user/bob">Bob</a>
44+
* </div>
45+
* ```
46+
*
47+
* This will set the active-link class on the div tag if the url is either '/user/jim' or
48+
* '/user/bob'.
49+
*
50+
* @stable
51+
*/
52+
@Directive({ selector: '[nsRouterLinkActive]' })
53+
export class NSRouterLinkActive implements OnChanges, OnDestroy, AfterContentInit {
54+
@ContentChildren(NSRouterLink) links: QueryList<NSRouterLink>;
55+
56+
private classes: string[] = [];
57+
private subscription: Subscription;
58+
59+
@Input() private nsRouterLinkActiveOptions: { exact: boolean } = { exact: false };
60+
61+
constructor(private router: Router, private element: ElementRef, private renderer: Renderer) {
62+
this.subscription = router.events.subscribe(s => {
63+
if (s instanceof NavigationEnd) {
64+
this.update();
65+
}
66+
});
67+
}
68+
69+
ngAfterContentInit(): void {
70+
this.links.changes.subscribe(s => this.update());
71+
this.update();
72+
}
73+
74+
@Input("nsRouterLinkActive")
75+
set nsRouterLinkActive(data: string[] | string) {
76+
if (Array.isArray(data)) {
77+
this.classes = <any>data;
78+
} else {
79+
this.classes = data.split(' ');
80+
}
81+
}
82+
83+
ngOnChanges(changes: {}): any { this.update(); }
84+
ngOnDestroy(): any { this.subscription.unsubscribe(); }
85+
86+
private update(): void {
87+
if (!this.links) return;
88+
89+
const currentUrlTree = this.router.parseUrl(this.router.url);
90+
const isActiveLinks = this.reduceList(currentUrlTree, this.links);
91+
this.classes.forEach(
92+
c => this.renderer.setElementClass(
93+
this.element.nativeElement, c, isActiveLinks));
94+
}
95+
96+
private reduceList(currentUrlTree: UrlTree, q: QueryList<any>): boolean {
97+
return q.reduce(
98+
(res: boolean, link: NSRouterLink) =>
99+
res || containsTree(currentUrlTree, link.urlTree, this.nsRouterLinkActiveOptions.exact),
100+
false);
101+
}
102+
}

nativescript-angular/router/ns-router-link.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {Router, ActivatedRoute, UrlTree} from '@angular/router';
44
import {routerLog} from "../trace";
55

66
/**
7-
* The RouterLink directive lets you link to specific parts of your app.
7+
* The NSRouterLink directive lets you link to specific parts of your app.
88
*
99
* Consider the following route configuration:
1010
@@ -18,7 +18,7 @@ import {routerLog} from "../trace";
1818
* <a [nsRouterLink]="['/user']">link to user component</a>
1919
* ```
2020
*
21-
* RouterLink expects the value to be an array of path segments, followed by the params
21+
* NSRouterLink expects the value to be an array of path segments, followed by the params
2222
* for that level of routing. For instance `['/team', {teamId: 1}, 'user', {userId: 2}]`
2323
* means that we want to generate a link to `/team;teamId=1/user;userId=2`.
2424
*
@@ -30,30 +30,41 @@ import {routerLog} from "../trace";
3030
*/
3131
@Directive({ selector: '[nsRouterLink]' })
3232
export class NSRouterLink {
33-
private commands: any[] = [];
34-
@Input() target: string;
35-
@Input() queryParams: { [k: string]: any };
36-
@Input() fragment: string;
33+
private commands: any[] = [];
34+
@Input() target: string;
35+
@Input() queryParams: { [k: string]: any };
36+
@Input() fragment: string;
3737

38-
/**
39-
* @internal
40-
*/
41-
constructor(private router: Router, private route: ActivatedRoute) { }
38+
urlTree: UrlTree;
39+
/**
40+
* @internal
41+
*/
42+
constructor(private router: Router, private route: ActivatedRoute) { }
4243

43-
@Input("nsRouterLink")
44-
set params(data: any[] | string) {
45-
if (Array.isArray(data)) {
46-
this.commands = data;
47-
} else {
48-
this.commands = [data];
44+
@Input("nsRouterLink")
45+
set params(data: any[] | string) {
46+
if (Array.isArray(data)) {
47+
this.commands = data;
48+
} else {
49+
this.commands = [data];
50+
}
4951
}
50-
}
5152

52-
@HostListener("tap")
53-
onTap() {
54-
routerLog("nsRouterLink.tapped: " + this.commands);
55-
this.router.navigate(
56-
this.commands,
57-
{ relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment });
58-
}
53+
ngOnChanges(changes: {}): any {
54+
this.updateTargetUrl();
55+
}
56+
57+
@HostListener("tap")
58+
onTap() {
59+
routerLog("nsRouterLink.tapped: " + this.commands);
60+
this.router.navigate(
61+
this.commands,
62+
{ relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment });
63+
}
64+
65+
private updateTargetUrl(): void {
66+
this.urlTree = this.router.createUrlTree(
67+
this.commands,
68+
{ relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment });
69+
}
5970
}

nativescript-angular/router/ns-router.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { RouterConfig } from '@angular/router';
55
import { provideRouter, ExtraOptions } from '@angular/router/common_router_providers';
66

77
import {NSRouterLink} from './ns-router-link';
8+
import {NSRouterLinkActive} from './ns-router-link-active';
89
import {PageRouterOutlet} from './page-router-outlet';
910
import {NSLocationStrategy} from './ns-location-strategy';
1011
import {NativescriptPlatformLocation} from './ns-platform-location';
@@ -22,6 +23,7 @@ export const NS_ROUTER_PROVIDERS: any[] = [
2223

2324
export const NS_ROUTER_DIRECTIVES: Type[] = [
2425
NSRouterLink,
26+
NSRouterLinkActive,
2527
PageRouterOutlet
2628
];
2729

@@ -30,4 +32,4 @@ export function nsProvideRouter(config: RouterConfig, opts: ExtraOptions): any[]
3032
...NS_ROUTER_PROVIDERS,
3133
...provideRouter(config, opts)
3234
]
33-
};
35+
};

0 commit comments

Comments
 (0)