Skip to content

Commit

Permalink
feat(LinkActive): Added override of default activeOptions for linkAct…
Browse files Browse the repository at this point in the history
…ive directive
  • Loading branch information
brandonroberts authored and Brandon Roberts committed Jun 3, 2016
1 parent 2acc88c commit 45269a3
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 6 deletions.
12 changes: 12 additions & 0 deletions docs/overview/links.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,15 @@ In order to keep a parent link active when the child path is active, use the `ac
<a linkActive="active red" linkTo="/blogs/pages/1">Page 1</a>
</subnav>
```

## Default Link Active Options

To override the default `activeOptions` for the `linkActive` directive, provide the `LINK_ACTIVE_OPTIONS` token in the bootstrap array of the application.

```ts
import {LINK_ACTIVE_OPTIONS} from '@ngrx/router';

bootstrap(App, [
provide(LINK_ACTIVE_OPTIONS, { useValue: { exact: false } })
])
```
2 changes: 1 addition & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,6 @@ export { PRE_RENDER_HOOKS, POST_RENDER_HOOKS, RenderInstruction } from './compon
export { Routes, Route, IndexRoute } from './route';
export { TRAVERSAL_HOOKS, TraversalCandidate, Match } from './route-traverser';
export { LinkTo } from './link-to';
export { LinkActive, LinkActiveOptions } from './link-active';
export { LinkActive, LinkActiveOptions, LINK_ACTIVE_OPTIONS } from './link-active';
export { RouteView } from './route-view';
export { Hook } from './hooks';
25 changes: 21 additions & 4 deletions lib/link-active.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
OnDestroy,
Query,
QueryList,
Renderer
Renderer,
Optional,
OpaqueToken,
Inject
} from '@angular/core';
import { LinkTo } from './link-to';
import { Router } from './router';
Expand All @@ -15,6 +18,10 @@ export interface LinkActiveOptions {
exact: boolean;
}

export const LINK_ACTIVE_OPTIONS: LinkActiveOptions = {
exact: true
};

/**
* The LinkActive directive toggles classes on elements that contain an active linkTo directive
*
Expand All @@ -28,17 +35,27 @@ export interface LinkActiveOptions {
@Directive({ selector: '[linkActive]' })
export class LinkActive implements AfterViewInit, OnDestroy {
@Input('linkActive') activeClass: string = 'active';
@Input() activeOptions: LinkActiveOptions = { exact: true };
@Input() activeOptions: LinkActiveOptions;
private _sub: any;
private _activeOptions: LinkActiveOptions = { exact: true };

constructor(
@Query(LinkTo) public links: QueryList<LinkTo>,
public element: ElementRef,
public router$: Router,
public renderer: Renderer
public renderer: Renderer,
@Optional()
@Inject(LINK_ACTIVE_OPTIONS)
private defaultActiveOptions: LinkActiveOptions
) {}

ngAfterViewInit() {
if (this.defaultActiveOptions && !this.activeOptions) {
this._activeOptions = this.defaultActiveOptions;
} else if (this.activeOptions) {
this._activeOptions = this.activeOptions;
}

this._sub = this.router$
.map(({path}) => this.router$.prepareExternalUrl(path || '/'))
.subscribe(path => {
Expand All @@ -50,7 +67,7 @@ export interface LinkActiveOptions {
let active = this.links.reduce((active, current) => {
let [href, query] = current.linkHref.split('?');

if (this.activeOptions.exact) {
if (this._activeOptions.exact) {
return active ? active : href === path;
} else {
return active ? active : path.startsWith(href);
Expand Down
50 changes: 49 additions & 1 deletion spec/link-active.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { LinkTo } from '../lib/link-to';
import { LinkActive } from '../lib/link-active';
import { LinkActive, LINK_ACTIVE_OPTIONS } from '../lib/link-active';
import { ROUTER_PROVIDERS, Router } from '../lib/router';

@Component({
Expand Down Expand Up @@ -185,4 +185,52 @@ describe('Link Active', () => {
});
})));
});

describe('With Default Link Active Options', () => {
beforeEachProviders(() => [
ROUTER_PROVIDERS,
provide(LocationStrategy, { useClass: MockLocationStrategy }),
provide(LINK_ACTIVE_OPTIONS, { useValue: { exact: false } })
]);

it('should allow override of default LinkActiveOptions', async(inject([TestComponentBuilder, Router], (tcb, router$) => {
router$.next({
path: '/pages/page2'
});

return compile(tcb, `
<a id="pages" linkActive="active" linkTo="/pages">Pages</a><br>
<a id="page2" linkActive="active" linkTo="/pages/page2">Page 2</a><br>
`)
.then((fixture) => {
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement;
let pagesLink: Element = compiled.querySelector('#pages');
let page2Link: Element = compiled.querySelector('#page2');

expect(pagesLink.getAttribute('class')).toEqual('active');
expect(page2Link.getAttribute('class')).toEqual('active');
});
})));

it('should allow local override of default LinkActiveOptions', async(inject([TestComponentBuilder, Router], (tcb, router$) => {
router$.next({
path: '/pages/page2'
});

return compile(tcb, `
<a id="pages" linkActive="active" linkTo="/pages" [activeOptions]="{ exact: true }">Pages</a><br>
<a id="page2" linkActive="active" linkTo="/pages/page2">Page 2</a><br>
`)
.then((fixture) => {
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement;
let pagesLink: Element = compiled.querySelector('#pages');
let page2Link: Element = compiled.querySelector('#page2');

expect(pagesLink.getAttribute('class')).not.toEqual('active');
expect(page2Link.getAttribute('class')).toEqual('active');
});
})));
});
});

0 comments on commit 45269a3

Please sign in to comment.