diff --git a/nativescript-angular/router/ns-router-link-active.ts b/nativescript-angular/router/ns-router-link-active.ts new file mode 100644 index 000000000..699485226 --- /dev/null +++ b/nativescript-angular/router/ns-router-link-active.ts @@ -0,0 +1,102 @@ +import {AfterContentInit, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer} from '@angular/core'; +import {Subscription} from 'rxjs/Subscription'; + +import {NavigationEnd, Router} from '@angular/router/router'; +import {UrlTree, containsTree} from '@angular/router/url_tree'; + +import {NSRouterLink} from './ns-router-link'; + + +/** + * The NSRouterLinkActive directive lets you add a CSS class to an element when the link's route + * becomes active. + * + * Consider the following example: + * + * ``` + * Bob + * ``` + * + * When the url is either '/user' or '/user/bob', the active-link class will + * be added to the component. If the url changes, the class will be removed. + * + * You can set more than one class, as follows: + * + * ``` + * Bob + * Bob + * ``` + * + * You can configure NSRouterLinkActive by passing `exact: true`. This will add the classes + * only when the url matches the link exactly. + * + * ``` + * Bob + * ``` + * + * Finally, you can apply the NSRouterLinkActive directive to an ancestor of a RouterLink. + * + * ``` + *
+ * Jim + * Bob + *
+ * ``` + * + * This will set the active-link class on the div tag if the url is either '/user/jim' or + * '/user/bob'. + * + * @stable + */ +@Directive({ selector: '[nsRouterLinkActive]' }) +export class NSRouterLinkActive implements OnChanges, OnDestroy, AfterContentInit { + @ContentChildren(NSRouterLink) links: QueryList; + + private classes: string[] = []; + private subscription: Subscription; + + @Input() private nsRouterLinkActiveOptions: { exact: boolean } = { exact: false }; + + 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()); + this.update(); + } + + @Input("nsRouterLinkActive") + set nsRouterLinkActive(data: string[] | string) { + if (Array.isArray(data)) { + this.classes = data; + } else { + this.classes = data.split(' '); + } + } + + ngOnChanges(changes: {}): any { this.update(); } + ngOnDestroy(): any { this.subscription.unsubscribe(); } + + private update(): void { + if (!this.links) return; + + const currentUrlTree = this.router.parseUrl(this.router.url); + const isActiveLinks = this.reduceList(currentUrlTree, this.links); + this.classes.forEach( + c => this.renderer.setElementClass( + this.element.nativeElement, c, isActiveLinks)); + } + + private reduceList(currentUrlTree: UrlTree, q: QueryList): boolean { + return q.reduce( + (res: boolean, link: NSRouterLink) => + res || containsTree(currentUrlTree, link.urlTree, this.nsRouterLinkActiveOptions.exact), + false); + } +} diff --git a/nativescript-angular/router/ns-router-link.ts b/nativescript-angular/router/ns-router-link.ts index 9b0af03fb..31835a3a3 100644 --- a/nativescript-angular/router/ns-router-link.ts +++ b/nativescript-angular/router/ns-router-link.ts @@ -4,7 +4,7 @@ import {Router, ActivatedRoute, UrlTree} from '@angular/router'; import {routerLog} from "../trace"; /** - * The RouterLink directive lets you link to specific parts of your app. + * The NSRouterLink directive lets you link to specific parts of your app. * * Consider the following route configuration: @@ -18,7 +18,7 @@ import {routerLog} from "../trace"; * link to user component * ``` * - * RouterLink expects the value to be an array of path segments, followed by the params + * NSRouterLink expects the value to be an array of path segments, followed by the params * for that level of routing. For instance `['/team', {teamId: 1}, 'user', {userId: 2}]` * means that we want to generate a link to `/team;teamId=1/user;userId=2`. * @@ -30,30 +30,41 @@ import {routerLog} from "../trace"; */ @Directive({ selector: '[nsRouterLink]' }) export class NSRouterLink { - private commands: any[] = []; - @Input() target: string; - @Input() queryParams: { [k: string]: any }; - @Input() fragment: string; + private commands: any[] = []; + @Input() target: string; + @Input() queryParams: { [k: string]: any }; + @Input() fragment: string; - /** - * @internal - */ - constructor(private router: Router, private route: ActivatedRoute) { } + urlTree: UrlTree; + /** + * @internal + */ + constructor(private router: Router, private route: ActivatedRoute) { } - @Input("nsRouterLink") - set params(data: any[] | string) { - if (Array.isArray(data)) { - this.commands = data; - } else { - this.commands = [data]; + @Input("nsRouterLink") + set params(data: any[] | string) { + if (Array.isArray(data)) { + this.commands = data; + } else { + this.commands = [data]; + } } - } - @HostListener("tap") - onTap() { - routerLog("nsRouterLink.tapped: " + this.commands); - this.router.navigate( - this.commands, - { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment }); - } + ngOnChanges(changes: {}): any { + this.updateTargetUrl(); + } + + @HostListener("tap") + onTap() { + routerLog("nsRouterLink.tapped: " + this.commands); + this.router.navigate( + this.commands, + { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment }); + } + + private updateTargetUrl(): void { + this.urlTree = this.router.createUrlTree( + this.commands, + { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment }); + } } diff --git a/nativescript-angular/router/ns-router.ts b/nativescript-angular/router/ns-router.ts index 81f26b65e..36d324676 100644 --- a/nativescript-angular/router/ns-router.ts +++ b/nativescript-angular/router/ns-router.ts @@ -5,6 +5,7 @@ import { RouterConfig } from '@angular/router'; import { provideRouter, ExtraOptions } from '@angular/router/common_router_providers'; import {NSRouterLink} from './ns-router-link'; +import {NSRouterLinkActive} from './ns-router-link-active'; import {PageRouterOutlet} from './page-router-outlet'; import {NSLocationStrategy} from './ns-location-strategy'; import {NativescriptPlatformLocation} from './ns-platform-location'; @@ -22,6 +23,7 @@ export const NS_ROUTER_PROVIDERS: any[] = [ export const NS_ROUTER_DIRECTIVES: Type[] = [ NSRouterLink, + NSRouterLinkActive, PageRouterOutlet ]; @@ -30,4 +32,4 @@ export function nsProvideRouter(config: RouterConfig, opts: ExtraOptions): any[] ...NS_ROUTER_PROVIDERS, ...provideRouter(config, opts) ] -}; \ No newline at end of file +};