Skip to content

Implemented nsRouterLinkActive directive (angular2 routerLinkActive) #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions nativescript-angular/router/ns-router-link-active.ts
Original file line number Diff line number Diff line change
@@ -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:
*
* ```
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="active-link">Bob</a>
* ```
*
* 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:
*
* ```
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="class1 class2">Bob</a>
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="['class1', 'class2']">Bob</a>
* ```
*
* You can configure NSRouterLinkActive by passing `exact: true`. This will add the classes
* only when the url matches the link exactly.
*
* ```
* <a [nsRouterLink]="/user/bob" [nsRouterLinkActive]="active-link" [nsRouterLinkActiveOptions]="{exact:
* true}">Bob</a>
* ```
*
* Finally, you can apply the NSRouterLinkActive directive to an ancestor of a RouterLink.
*
* ```
* <div [nsRouterLinkActive]="active-link" [nsRouterLinkActiveOptions]="{exact: true}">
* <a [nsRouterLink]="/user/jim">Jim</a>
* <a [nsRouterLink]="/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'.
*
* @stable
*/
@Directive({ selector: '[nsRouterLinkActive]' })
export class NSRouterLinkActive implements OnChanges, OnDestroy, AfterContentInit {
@ContentChildren(NSRouterLink) links: QueryList<NSRouterLink>;

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 = <any>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<any>): boolean {
return q.reduce(
(res: boolean, link: NSRouterLink) =>
res || containsTree(currentUrlTree, link.urlTree, this.nsRouterLinkActiveOptions.exact),
false);
}
}
59 changes: 35 additions & 24 deletions nativescript-angular/router/ns-router-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -18,7 +18,7 @@ import {routerLog} from "../trace";
* <a [nsRouterLink]="['/user']">link to user component</a>
* ```
*
* 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`.
*
Expand All @@ -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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
* @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 });
}
}
4 changes: 3 additions & 1 deletion nativescript-angular/router/ns-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -22,6 +23,7 @@ export const NS_ROUTER_PROVIDERS: any[] = [

export const NS_ROUTER_DIRECTIVES: Type[] = [
NSRouterLink,
NSRouterLinkActive,
PageRouterOutlet
];

Expand All @@ -30,4 +32,4 @@ export function nsProvideRouter(config: RouterConfig, opts: ExtraOptions): any[]
...NS_ROUTER_PROVIDERS,
...provideRouter(config, opts)
]
};
};