Skip to content

Commit

Permalink
refactor(): Use @ngrx/core package for common utilities (#100)
Browse files Browse the repository at this point in the history
Uses `SyncSubject`, `enterZone`, and `compose` from @ngrx/core

BREAKING CHANGE:

  You will now have to install @ngrx/core in addition to @ngrx/router
  • Loading branch information
MikeRyanDev authored and brandonroberts committed May 13, 2016
1 parent ede340d commit 10cc353
Show file tree
Hide file tree
Showing 12 changed files with 37 additions and 148 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ This is an alternative router for Angular 2 focused on providing a simple, react
Please note that we are currently pre-v1.0. While we believe the core of the router is solid, you can expect a few breaking changes as we work towards a beta release. These early releases are meant to gather feedback from the community and to help with the direction of the router.

### Installation
Install @ngrx/router into your Angular 2 project via npm:
Install @ngrx/router and @ngrx/core into your Angular 2 project via npm:

```
npm install @ngrx/router --save
npm install @ngrx/router @ngrx/core --save
```

### Routing Setup
Expand Down
1 change: 0 additions & 1 deletion lib/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import 'rxjs/add/operator/every';
import { Observable } from 'rxjs/Observable';
import { Inject, Injectable, Provider, OpaqueToken, Injector, ReflectiveInjector } from '@angular/core';

import { createProviderFactory } from './util';
import { Route } from './route';
import { TRAVERSAL_HOOKS, TraversalCandidate } from './route-traverser';
import { Hook } from './hooks';
Expand Down
2 changes: 1 addition & 1 deletion lib/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Observable } from 'rxjs/Observable';
import { compose } from './util';
import { compose } from '@ngrx/core/compose';

export interface Hook<T> {
apply(input$: Observable<T>): Observable<T>;
Expand Down
4 changes: 1 addition & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { MATCH_ROUTE_PROVIDERS } from './route-traverser';
import { COMPONENT_RENDERER_PROVIDERS } from './component-renderer';
import { PARAMS_PROVIDERS } from './params';
import { RESOURCE_LOADER_PROVIDERS } from './resource-loader';
import { ZONE_OPERATOR_PROVIDERS } from './zone';

// Directives
import { LinkTo } from './link-to';
Expand All @@ -28,8 +27,7 @@ export const ROUTER_PROVIDERS = [
REDIRECT_PROVIDERS,
RESOURCE_LOADER_PROVIDERS,
ROUTER_INSTRUCTION_PROVIDERS,
ROUTER_SERVICE_PROVIDERS,
ZONE_OPERATOR_PROVIDERS
ROUTER_SERVICE_PROVIDERS
];

// Export all router directives
Expand Down
8 changes: 4 additions & 4 deletions lib/router-instruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import 'rxjs/add/operator/publishReplay';
import 'rxjs/add/operator/let';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/observeOn';
import '@ngrx/core/add/operator/enterZone';
import { Observable } from 'rxjs/Observable';
import { asap } from 'rxjs/scheduler/asap';
import { Provider, Injector, OpaqueToken, Inject, Optional, Injectable } from '@angular/core';
import { Provider, Injector, OpaqueToken, Inject, Optional, Injectable, NgZone } from '@angular/core';
import { parse as parseQueryString } from 'query-string';

import { ZoneOperator } from './zone';
import { Router, LocationChange } from './router';
import { Routes, Route, ROUTES } from './route';
import { RouteTraverser, Match } from './route-traverser';
Expand All @@ -31,7 +31,7 @@ export class RouterInstructionFactory {
constructor(
@Inject(LOCATION_CHANGES) private _locationChanges$: Observable<LocationChange>,
private _traverser: RouteTraverser,
private _zoneOperator: ZoneOperator<Match>,
private _ngZone: NgZone,
@Optional() @Inject(ROUTER_HOOKS)
private _routerHooks: Hook<LocationChange>[] = [],
@Optional() @Inject(INSTRUCTION_HOOKS)
Expand All @@ -46,7 +46,7 @@ export class RouterInstructionFactory {
.switchMap(change => this._traverser.find(change))
.filter(match => !!match)
.let(composeHooks(this._instructionHooks))
.lift(this._zoneOperator)
.enterZone(this._ngZone)
.publishReplay(1)
.refCount();
}
Expand Down
41 changes: 26 additions & 15 deletions lib/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,28 @@
* It exposes location updates as a BehaviorSubject, letting the router
* observe location changes.
*/
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Subscriber } from 'rxjs/Subscriber';
import { LocationStrategy, UrlChangeEvent, PlatformLocation } from '@angular/common';
import { BrowserPlatformLocation } from '@angular/platform-browser';
import { Injectable, Inject, Provider, provide } from '@angular/core';
import { stringify as stringifyQueryParams } from 'query-string';
import { SyncSubject } from '@ngrx/core/SyncSubject';

export interface LocationChange {
path: string;
type: 'push' | 'pop' | 'replace';
}

@Injectable()
export class Router extends ReplaySubject<LocationChange> {
export class Router extends SyncSubject<LocationChange> {
private _baseHref: string;

constructor(public platformStrategy: LocationStrategy) {
super(1);
super({ path: _path(platformStrategy), type: 'push' });

platformStrategy.onPopState(event => this._update('pop'));

const browserBaseHref = this.platformStrategy.getBaseHref();
this._baseHref = stripTrailingSlash(stripIndexHtml(browserBaseHref));
this._update('push');
this._baseHref = _getBaseHref(platformStrategy);
}

private _update(type: 'push' | 'pop' | 'replace') {
Expand All @@ -37,15 +35,15 @@ export class Router extends ReplaySubject<LocationChange> {
* Returns the normalized URL path.
*/
path(): string {
return this.normalize(this.platformStrategy.path());
return _path(this.platformStrategy);
}

/**
* Given a string representing a URL, returns the normalized URL path without leading or
* trailing slashes
*/
normalize(url: string): string {
return stripTrailingSlash(_stripBaseHref(this._baseHref, stripIndexHtml(url)));
return _normalize(this._baseHref, url);
}

/**
Expand All @@ -58,15 +56,15 @@ export class Router extends ReplaySubject<LocationChange> {
if (url.length > 0 && !url.startsWith('/')) {
url = '/' + url;
}
return this.platformStrategy.prepareExternalUrl(url + normalizeQueryParams(normalizeQuery(query)));
return this.platformStrategy.prepareExternalUrl(url + _normalizeQueryParams(_normalizeQuery(query)));
}

/**
* Changes the browsers URL to the normalized version of the given URL, and pushes a
* new item onto the platform's history.
*/
go(path: string, query: any = ''): void {
this.platformStrategy.pushState(null, '', path, normalizeQuery(query));
this.platformStrategy.pushState(null, '', path, _normalizeQuery(query));
this._update('push');
}

Expand All @@ -75,7 +73,7 @@ export class Router extends ReplaySubject<LocationChange> {
* the top item on the platform's history stack.
*/
replace(path: string, query: any = ''): void {
this.platformStrategy.replaceState(null, '', path, normalizeQuery(query));
this.platformStrategy.replaceState(null, '', path, _normalizeQuery(query));
this._update('replace');
}

Expand Down Expand Up @@ -104,33 +102,46 @@ export class Router extends ReplaySubject<LocationChange> {
}
}

function _path(location: LocationStrategy): string {
return _normalize(_getBaseHref(location), location.path());
}

function _normalize(baseHref: string, url: string): string {
return _stripTrailingSlash(_stripBaseHref(baseHref, _stripIndexHtml(url)));
}

function _getBaseHref(platformStrategy): string {
const browserBaseHref = platformStrategy.getBaseHref();
return _stripTrailingSlash(_stripIndexHtml(browserBaseHref));
}

function _stripBaseHref(baseHref: string, url: string): string {
if (baseHref.length > 0 && url.startsWith(baseHref)) {
return url.substring(baseHref.length);
}
return url;
}

function stripIndexHtml(url: string): string {
function _stripIndexHtml(url: string): string {
if (/\/index.html$/g.test(url)) {
// '/index.html'.length == 11
return url.substring(0, url.length - 11);
}
return url;
}

function stripTrailingSlash(url: string): string {
function _stripTrailingSlash(url: string): string {
if (/\/$/g.test(url)) {
url = url.substring(0, url.length - 1);
}
return url;
}

function normalizeQuery(query: any) {
function _normalizeQuery(query: any) {
return typeof query === 'string' ? query : stringifyQueryParams(query);
}

function normalizeQueryParams(params: string): string {
function _normalizeQueryParams(params: string): string {
return (params.length > 0 && params.substring(0, 1) !== '?') ? ('?' + params) : params;
}

Expand Down
31 changes: 0 additions & 31 deletions lib/util.ts

This file was deleted.

27 changes: 0 additions & 27 deletions lib/zone.ts

This file was deleted.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
],
"license": "MIT",
"peerDependencies": {
"@ngrx/core": "^1.0.0",
"rxjs": "^5.0.0-beta.6",
"@angular/core": "^2.0.0-rc.1",
"@angular/platform-browser": "^2.0.0-rc.1",
Expand All @@ -49,6 +50,7 @@
"@angular/http": "^2.0.0-rc.1",
"@angular/platform-browser": "^2.0.0-rc.1",
"@angular/platform-browser-dynamic": "^2.0.0-rc.1",
"@ngrx/core": "^1.0.0",
"conventional-changelog-cli": "^1.1.1",
"core-js": "^2.2.2",
"esdoc": "^0.4.6",
Expand Down
4 changes: 1 addition & 3 deletions spec/router-instruction.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import 'rxjs/add/operator/withLatestFrom';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import { ReflectiveInjector, provide, NgZone } from '@angular/core';
import { ReflectiveInjector, provide, NgZone, createNgZone } from '@angular/core';
import { LocationStrategy } from '@angular/common';
import { MockLocationStrategy } from '@angular/common/testing';

import { RouteTraverser } from '../lib/route-traverser';
import { Router, ROUTER_PROVIDERS } from '../lib/router';
import { RouterInstruction, ROUTER_INSTRUCTION_PROVIDERS } from '../lib/router-instruction';
import { ZONE_OPERATOR_PROVIDERS } from '../lib/zone';
import { Match } from '../lib/route-traverser';


Expand Down Expand Up @@ -45,7 +44,6 @@ describe('Router Instruction', function() {
const injector = ReflectiveInjector.resolveAndCreate([
ROUTER_PROVIDERS,
ROUTER_INSTRUCTION_PROVIDERS,
ZONE_OPERATOR_PROVIDERS,
provide(RouteTraverser, { useValue: mockTraverser }),
provide(LocationStrategy, { useClass: MockLocationStrategy }),
provide(NgZone, { useValue: mockZone })
Expand Down
1 change: 0 additions & 1 deletion spec/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"./route.spec.ts",
"./router-instruction.spec.ts",
"./router.spec.ts",
"./util.spec.ts",
"../typings/main.d.ts",
"../manual-typings/path-to-regexp.d.ts"
],
Expand Down
60 changes: 0 additions & 60 deletions spec/util.spec.ts

This file was deleted.

0 comments on commit 10cc353

Please sign in to comment.