diff --git a/docs/overview/links.md b/docs/overview/links.md
index c29bd7e..8b6f440 100644
--- a/docs/overview/links.md
+++ b/docs/overview/links.md
@@ -57,3 +57,15 @@ In order to keep a parent link active when the child path is active, use the `ac
Page 1
```
+
+## 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 } })
+])
+```
diff --git a/lib/index.ts b/lib/index.ts
index e8db6cf..2b8d479 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -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';
diff --git a/lib/link-active.ts b/lib/link-active.ts
index 6c7bcf2..5c3b934 100644
--- a/lib/link-active.ts
+++ b/lib/link-active.ts
@@ -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';
@@ -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
*
@@ -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,
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 => {
@@ -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);
diff --git a/spec/link-active.spec.ts b/spec/link-active.spec.ts
index d92d091..3477de7 100644
--- a/spec/link-active.spec.ts
+++ b/spec/link-active.spec.ts
@@ -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({
@@ -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, `
+ Pages
+ Page 2
+ `)
+ .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, `
+ Pages
+ Page 2
+ `)
+ .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');
+ });
+ })));
+ });
});