refactor(router): monkey patch the router instead of extending it

This commit is contained in:
Dan Bucholtz
2018-02-15 13:49:44 -06:00
parent e8cd91f45e
commit 8ec8b43408
77 changed files with 197 additions and 25878 deletions

View File

@ -11,7 +11,6 @@ export { VirtualFooter } from './directives/virtual-footer';
export { RouterOutlet } from './router/outlet';
export { AsyncActivateRoutes } from './router/async-activated-routes';
export { OutletInjector } from './router/outlet-injector';
export { CustomRouter } from './router/router';
export { IonicRouterModule } from './router/router-module';
/* Providers */

View File

@ -0,0 +1,103 @@
import {
Event,
NavigationCancel,
NavigationEnd,
NavigationError,
RouterState,
UrlTree
} from '@angular/router';
import { Observable } from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import { AsyncActivateRoutes } from './async-activated-routes';
export function monkeyPatchRouter(router: any) {
router.activateRoutes = (state: Observable<{appliedUrl: string, state: RouterState, shouldActivate: boolean}>, storedState: RouterState,
storedUrl: UrlTree, id: number, url: UrlTree, rawUrl: UrlTree, skipLocationChange: boolean, replaceUrl: boolean, resolvePromise: any, rejectPromise: any) => {
// applied the new router state
// this operation has side effects
let navigationIsSuccessful: boolean;
const routes: AsyncActivateRoutes[] = [];
state
.forEach(({appliedUrl, state, shouldActivate}: any) => {
if (!shouldActivate || id !== router.navigationId) {
navigationIsSuccessful = false;
return;
}
router.currentUrlTree = appliedUrl;
router.rawUrlTree = router.urlHandlingStrategy.merge(router.currentUrlTree, rawUrl);
(router as{routerState: RouterState}).routerState = state;
if (!skipLocationChange) {
const path = router.urlSerializer.serialize(router.rawUrlTree);
if (router.location.isCurrentPathEqualTo(path) || replaceUrl) {
router.location.replaceState(path, '');
} else {
router.location.go(path, '');
}
}
routes.push(new AsyncActivateRoutes(router.routeReuseStrategy, state, storedState, (evt: Event) => router.triggerEvent(evt)))
})
.then(
() => {
const promises = routes.map(activatedRoute => activatedRoute.activate(router.rootContexts));
return Promise.all(promises)
.then(
() => {
navigationIsSuccessful = true;
}
);
}
)
.then(
() => {
if (navigationIsSuccessful) {
router.navigated = true;
router.lastSuccessfulId = id;
(router.events as Subject<Event>)
.next(new NavigationEnd(
id, router.serializeUrl(url), router.serializeUrl(router.currentUrlTree)));
resolvePromise(true);
} else {
router.resetUrlToCurrentUrlTree();
(router.events as Subject<Event>)
.next(new NavigationCancel(id, router.serializeUrl(url), ''));
resolvePromise(false);
}
},
(e: any) => {
if (isNavigationCancelingError(e)) {
router.navigated = true;
router.resetStateAndUrl(storedState, storedUrl, rawUrl);
(router.events as Subject<Event>)
.next(new NavigationCancel(id, router.serializeUrl(url), e.message));
resolvePromise(false);
} else {
router.resetStateAndUrl(storedState, storedUrl, rawUrl);
(router.events as any as Subject<Event>)
.next(new NavigationError(id, router.serializeUrl(url), e));
try {
resolvePromise(router.errorHandler(e));
} catch (ee) {
rejectPromise(ee);
}
}
});
};
}
function isNavigationCancelingError(error: any) {
return error && (/** @type {?} */ (error))[NAVIGATION_CANCELING_ERROR];
}
const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';

View File

@ -191,7 +191,6 @@ export function getDataFromObservable(activatedRoute: ActivatedRoute) {
export function getDataFromParams(activatedRoute: ActivatedRoute) {
return new Promise((resolve) => {
activatedRoute.params.subscribe((data: any) => {
console.log('data: ', data);
resolve(data || {});
});
});

View File

@ -29,7 +29,7 @@ import {
import { IonicAngularModule } from '../module';
import { PushPopOutletContexts } from './push-pop-outlet-contexts';
import { CustomRouter } from './router';
import { monkeyPatchRouter } from './monkey-patch-router';
import { RouteEventHandler } from './route-event-handler';
import { RouterOutlet } from './outlet';
import { flatten } from './router-utils';
@ -75,9 +75,12 @@ export function setupRouter(
config: Route[][], opts: ExtraOptions = {}, urlHandlingStrategy?: UrlHandlingStrategy,
routeReuseStrategy?: RouteReuseStrategy) {
const router = new CustomRouter(
const router = new Router(
null, urlSerializer, contexts, location, injector, loader, compiler, flatten(config));
monkeyPatchRouter(router);
if (urlHandlingStrategy) {
router.urlHandlingStrategy = urlHandlingStrategy;
}

View File

@ -1,111 +0,0 @@
import {
Event,
NavigationCancel,
NavigationEnd,
NavigationError,
Router,
RouterState,
UrlTree
} from '@angular/router';
import { Observable } from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import { AsyncActivateRoutes } from './async-activated-routes';
export class CustomRouter extends Router {
protected activateRoutes(state: Observable<{appliedUrl: string, state: RouterState, shouldActivate: boolean}>, storedState: RouterState,
storedUrl: UrlTree, id: number, url: UrlTree, rawUrl: UrlTree, skipLocationChange: boolean, replaceUrl: boolean, resolvePromise: any, rejectPromise: any) {
// applied the new router state
// this operation has side effects
let navigationIsSuccessful: boolean;
const routes: AsyncActivateRoutes[] = [];
state
.forEach(({appliedUrl, state, shouldActivate}: any) => {
if (!shouldActivate || id !== this.navigationId) {
navigationIsSuccessful = false;
return;
}
this.currentUrlTree = appliedUrl;
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl);
(this as{routerState: RouterState}).routerState = state;
if (!skipLocationChange) {
const path = this.urlSerializer.serialize(this.rawUrlTree);
if (this.location.isCurrentPathEqualTo(path) || replaceUrl) {
this.location.replaceState(path, '');
} else {
this.location.go(path, '');
}
}
routes.push(new AsyncActivateRoutes(this.routeReuseStrategy, state, storedState, (evt: Event) => this.triggerEvent(evt)))
})
.then(
() => {
const promises = routes.map(activatedRoute => activatedRoute.activate(this.rootContexts));
return Promise.all(promises)
.then(
() => {
navigationIsSuccessful = true;
}
);
}
)
.then(
() => {
if (navigationIsSuccessful) {
this.navigated = true;
this.lastSuccessfulId = id;
(this.events as Subject<Event>)
.next(new NavigationEnd(
id, this.serializeUrl(url), this.serializeUrl(this.currentUrlTree)));
resolvePromise(true);
} else {
this.resetUrlToCurrentUrlTree();
(this.events as Subject<Event>)
.next(new NavigationCancel(id, this.serializeUrl(url), ''));
resolvePromise(false);
}
},
(e: any) => {
if (isNavigationCancelingError(e)) {
this.navigated = true;
this.resetStateAndUrl(storedState, storedUrl, rawUrl);
(this.events as Subject<Event>)
.next(new NavigationCancel(id, this.serializeUrl(url), e.message));
resolvePromise(false);
} else {
this.resetStateAndUrl(storedState, storedUrl, rawUrl);
(this.events as any as Subject<Event>)
.next(new NavigationError(id, this.serializeUrl(url), e));
try {
resolvePromise(this.errorHandler(e));
} catch (ee) {
rejectPromise(ee);
}
}
});
}
triggerEvent(e: Event): void { (this.events as any as Subject<Event>).next(e); }
serializeUrl(url: UrlTree): string { return this.urlSerializer.serialize(url); }
}
const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';
export function isNavigationCancelingError(error: Error) {
return error && (error as any)[NAVIGATION_CANCELING_ERROR];
}