Skip to content
This repository has been archived by the owner on Jul 27, 2018. It is now read-only.

Commit

Permalink
feat(actions): Added support for router NavigationExtras (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonroberts authored and MikeRyanDev committed Sep 13, 2016
1 parent db7c9b7 commit e30cf16
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 46 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,22 @@
```ts
store.dispatch(forward());
```

### Navigation Extras

The [Angular Router Navigation Extras](https://angular.io/docs/ts/latest/api/router/index/NavigationExtras-interface.html) are supported with each router action.

```ts
import { NavigationExtras } from '@angular/router';

let extras: NavigationExtras = {
relativeTo: ActivatedRoute,
fragment: string,
preserveQueryParams: boolean,
preserveFragment: boolean,
skipLocationChange: boolean,
replaceUrl: boolean
};

store.dispatch(go(['path', { routeParam: 1 }], { query: 'string' }, extras));
```
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@
],
"license": "MIT",
"peerDependencies": {
"rxjs": "^5.0.0-beta.6",
"@angular/common": "^2.0.0-rc.5",
"@angular/core": "^2.0.0-rc.5",
"@angular/router": "^3.0.0-rc.1",
"rxjs": "^5.0.0-beta.11",
"@angular/common": "^2.0.0-rc.6",
"@angular/core": "^2.0.0-rc.6",
"@angular/router": "^3.0.0-rc.2",
"@ngrx/store": "^1.5.0 || ^2.0.0"
},
"devDependencies": {
"@angular/common": "^2.0.0-rc.5",
"@angular/compiler": "^2.0.0-rc.5",
"@angular/common": "^2.0.0-rc.6",
"@angular/compiler": "^2.0.0-rc.6",
"@angular/compiler-cli": "^0.5.0",
"@angular/core": "^2.0.0-rc.5",
"@angular/platform-browser": "^2.0.0-rc.5",
"@angular/platform-browser-dynamic": "^2.0.0-rc.5",
"@angular/platform-server": "^2.0.0-rc.5",
"@angular/router": "^3.0.0-rc.1",
"@angular/core": "^2.0.0-rc.6",
"@angular/platform-browser": "^2.0.0-rc.6",
"@angular/platform-browser-dynamic": "^2.0.0-rc.6",
"@angular/platform-server": "^2.0.0-rc.6",
"@angular/router": "^3.0.0-rc.2",
"@ngrx/core": "^1.0.0",
"@ngrx/store": "^2.0.0",
"@types/jasmine": "^2.2.33",
Expand All @@ -69,12 +69,12 @@
"karma-webpack": "^1.7.0",
"npm-run-all": "^1.7.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"rxjs": "5.0.0-beta.11",
"source-map-loader": "^0.1.5",
"ts-loader": "^0.8.1",
"tslint": "^3.6.0",
"typescript": "^2.0.0",
"webpack": "^2.1.0-beta.21",
"zone.js": "0.6.12"
"zone.js": "^0.6.17"
}
}
21 changes: 14 additions & 7 deletions spec/actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ describe('Actions', function() {
type: actions.routerActions.GO,
payload: {
path: '/path',
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});

expect(actions.go(['/path'], { query: 'string' })).toEqual({
type: actions.routerActions.GO,
payload: {
path: ['/path'],
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});
});
Expand All @@ -24,15 +26,17 @@ describe('Actions', function() {
type: actions.routerActions.REPLACE,
payload: {
path: '/path',
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});

expect(actions.replace(['/path'], { query: 'string' })).toEqual({
type: actions.routerActions.REPLACE,
payload: {
path: ['/path'],
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});
});
Expand All @@ -42,15 +46,17 @@ describe('Actions', function() {
type: actions.routerActions.SHOW,
payload: {
path: '/path',
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});

expect(actions.show(['/path'], { query: 'string' })).toEqual({
type: actions.routerActions.SHOW,
payload: {
path: ['/path'],
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});
});
Expand All @@ -59,7 +65,8 @@ describe('Actions', function() {
expect(actions.search({ query: 'string' })).toEqual({
type: actions.routerActions.SEARCH,
payload: {
query: { query: 'string' }
query: { query: 'string' },
extras: undefined
}
});
});
Expand Down
63 changes: 51 additions & 12 deletions spec/connect.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'rxjs/add/observable/of';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Router, NavigationEnd } from '@angular/router';
import { Router, NavigationEnd, NavigationExtras } from '@angular/router';
import { Store } from '@ngrx/store';

import { RouterState } from '../src/reducer';
Expand All @@ -15,6 +15,13 @@ describe('Router/Store Connectors', function() {
let stringPath: string = '/path';
let stringArray: any[] = [stringPath];
let arrayPath: any[] = [stringPath, 1, { page: 1 }];
let queryParams: any = { queryParams: { query: 'string' } };
let extras: NavigationExtras = {
fragment: 'test',
relativeTo: null,
preserveFragment: true,
preserveQueryParams: true
};

beforeEach(function() {
location = {
Expand All @@ -38,14 +45,21 @@ describe('Router/Store Connectors', function() {
const action$ = Observable.of(routerActions.go(stringPath, { query: 'string' }));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(stringArray, { queryParams: { query: 'string' } });
expect(router.navigate).toHaveBeenCalledWith(stringArray, queryParams);
});

it('with an array', function() {
const action$ = Observable.of(routerActions.go(arrayPath, { query: 'string' }));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(['/path', 1, { page: 1 }], { queryParams: { query: 'string' } });
expect(router.navigate).toHaveBeenCalledWith(['/path', 1, { page: 1 }], queryParams);
});

it('with extras', function() {
const action$ = Observable.of(routerActions.go(arrayPath, { query: 'string' }, extras));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(['/path', 1, { page: 1 }], Object.assign({}, queryParams, extras));
});
});

Expand All @@ -54,38 +68,62 @@ describe('Router/Store Connectors', function() {
const action$ = Observable.of(routerActions.replace(stringPath, { query: 'string' }));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(stringArray, { queryParams: { query: 'string' }, replaceUrl: true });
expect(router.navigate).toHaveBeenCalledWith(stringArray, Object.assign({}, queryParams, { replaceUrl: true }));
});

it('with an array', function() {
const action$ = Observable.of(routerActions.replace(arrayPath, { query: 'string' }));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(arrayPath, { queryParams: { query: 'string' }, replaceUrl: true });
expect(router.navigate).toHaveBeenCalledWith(arrayPath, Object.assign({}, queryParams, { replaceUrl: true }));
});

it('with extras', function() {
const action$ = Observable.of(routerActions.replace(arrayPath, { query: 'string' }, extras));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(arrayPath, Object.assign({}, queryParams, { replaceUrl: true }, extras));
});
});
describe('should call Router@navigate when a "SHOW" action is dispatched', function() {
it('with a string', function() {
const action$ = Observable.of(routerActions.show(stringPath, { query: 'string' }));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(stringArray, { queryParams: { query: 'string' }, skipLocationChange: true });
expect(router.navigate).toHaveBeenCalledWith(stringArray, Object.assign({}, queryParams, { skipLocationChange: true }));
});

it('with an array', function() {
const action$ = Observable.of(routerActions.show(arrayPath, { query: 'string' }));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(arrayPath, { queryParams: { query: 'string' }, skipLocationChange: true });
expect(router.navigate).toHaveBeenCalledWith(arrayPath, Object.assign({}, queryParams, { skipLocationChange: true }));
});

it('with extras', function() {
const action$ = Observable.of(routerActions.show(arrayPath, { query: 'string' }, extras));
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).toHaveBeenCalledWith(arrayPath, Object.assign({}, queryParams, { skipLocationChange: true }, extras));
});
});

it('should call Router@navigate when a "SEARCH" action is dispatched', function() {
const action$ = Observable.of(routerActions.search({ query: 'string' }));
router.url = '/path';
listenForRouterMethodActions(router, location, action$);
describe('should call Router@navigate when a "SEARCH" action is dispatched', function() {
it('with query params', function() {
const action$ = Observable.of(routerActions.search({ query: 'string' }));
router.url = '/path';
listenForRouterMethodActions(router, location, action$);

expect(router.navigateByUrl).toHaveBeenCalledWith({ queryParams: { query: 'string' } });
expect(router.navigateByUrl).toHaveBeenCalledWith(queryParams, { });
});

it('with extras', function() {
const action$ = Observable.of(routerActions.search({ query: 'string' }, extras));
router.url = '/path';
listenForRouterMethodActions(router, location, action$);

expect(router.navigateByUrl).toHaveBeenCalledWith(queryParams, extras);
});
});

it('should call Location@back when a "BACK" action is dispatched', function() {
Expand All @@ -107,6 +145,7 @@ describe('Router/Store Connectors', function() {
listenForRouterMethodActions(router, location, action$);

expect(router.navigate).not.toHaveBeenCalled();
expect(router.navigateByUrl).not.toHaveBeenCalled();
expect(location.forward).not.toHaveBeenCalled();
expect(location.back).not.toHaveBeenCalled();
});
Expand Down
18 changes: 10 additions & 8 deletions src/actions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Action } from '@ngrx/store';
import { NavigationExtras } from '@angular/router';

export interface RouterMethodCall {
path?: string | any[];
query?: any;
extras?: NavigationExtras;
}

export const routerActions = {
Expand All @@ -17,26 +19,26 @@ export const routerActions = {

export const routerActionTypes = Object.keys(routerActions).map(key => routerActions[key]);

export function go(path: string|any[], query?: any): Action {
const payload: RouterMethodCall = { path, query };
export function go(path: string|any[], query?: any, extras?: NavigationExtras): Action {
const payload: RouterMethodCall = { path, query, extras };

return { type: routerActions.GO, payload };
}

export function replace(path: string|any[], query?: any): Action {
const payload: RouterMethodCall = { path, query };
export function replace(path: string|any[], query?: any, extras?: NavigationExtras): Action {
const payload: RouterMethodCall = { path, query, extras };

return { type: routerActions.REPLACE, payload };
}

export function search(query: any): Action {
const payload: RouterMethodCall = { query };
export function search(query: any, extras?: NavigationExtras): Action {
const payload: RouterMethodCall = { query, extras };

return { type: routerActions.SEARCH, payload };
}

export function show(path: string|any[], query?: any): Action {
const payload: RouterMethodCall = { path, query };
export function show(path: string|any[], query?: any, extras?: NavigationExtras): Action {
const payload: RouterMethodCall = { path, query, extras };

return { type: routerActions.SHOW, payload };
}
Expand Down
10 changes: 5 additions & 5 deletions src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@ export function listenForRouterMethodActions(router: Router, location: Location,
actions$
.filter(action => routerActionTypes.indexOf(action.type) > -1)
.subscribe(action => {
const { path, query: queryParams }: RouterMethodCall = action.payload;
const { path, query: queryParams, extras = {} }: RouterMethodCall = action.payload;
let commands: any[] = Array.isArray(path) ? path : [path];

switch (action.type) {
case routerActions.GO:
router.navigate(commands, { queryParams });
router.navigate(commands, Object.assign({}, extras, { queryParams }));
break;

case routerActions.REPLACE:
router.navigate(commands, <any>({ queryParams, replaceUrl: true }));
router.navigate(commands, Object.assign({}, extras, <any>({ queryParams, replaceUrl: true })));
break;

case routerActions.SEARCH:
let urlTree: UrlTree = router.parseUrl(router.url);
urlTree.queryParams = queryParams;
router.navigateByUrl(urlTree);
router.navigateByUrl(urlTree, extras);
break;

case routerActions.SHOW:
router.navigate(commands, { queryParams, skipLocationChange: true });
router.navigate(commands, Object.assign({}, extras, { queryParams, skipLocationChange: true }));
break;

case routerActions.BACK:
Expand Down
6 changes: 5 additions & 1 deletion tests.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import 'core-js';
import 'core-js/es7/reflect';

import 'zone.js/dist/zone';
import 'zone.js/dist/proxy';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/sync-test';



// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
Expand Down

0 comments on commit e30cf16

Please sign in to comment.