parent
601fd3e305
commit
7df6f46c1c
|
@ -233,7 +233,7 @@ class ApplyRedirects {
|
||||||
segments: UrlSegment[]): Observable<UrlSegmentGroup> {
|
segments: UrlSegment[]): Observable<UrlSegmentGroup> {
|
||||||
if (route.path === '**') {
|
if (route.path === '**') {
|
||||||
if (route.loadChildren) {
|
if (route.loadChildren) {
|
||||||
return map.call(this.configLoader.load(injector, route.loadChildren), (r: any) => {
|
return map.call(this.configLoader.load(injector, route), (r: any) => {
|
||||||
(<any>route)._loadedConfig = r;
|
(<any>route)._loadedConfig = r;
|
||||||
return new UrlSegmentGroup(segments, {});
|
return new UrlSegmentGroup(segments, {});
|
||||||
});
|
});
|
||||||
|
@ -281,7 +281,7 @@ class ApplyRedirects {
|
||||||
if ((<any>route)._loadedConfig) {
|
if ((<any>route)._loadedConfig) {
|
||||||
return of ((<any>route)._loadedConfig);
|
return of ((<any>route)._loadedConfig);
|
||||||
} else {
|
} else {
|
||||||
return map.call(this.configLoader.load(injector, route.loadChildren), (r: any) => {
|
return map.call(this.configLoader.load(injector, route), (r: any) => {
|
||||||
(<any>route)._loadedConfig = r;
|
(<any>route)._loadedConfig = r;
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,8 @@ import {Attribute, Directive, ElementRef, HostBinding, HostListener, Input, OnCh
|
||||||
import {Subscription} from 'rxjs/Subscription';
|
import {Subscription} from 'rxjs/Subscription';
|
||||||
|
|
||||||
import {QueryParamsHandling} from '../config';
|
import {QueryParamsHandling} from '../config';
|
||||||
import {NavigationEnd, Router} from '../router';
|
import {NavigationEnd} from '../events';
|
||||||
|
import {Router} from '../router';
|
||||||
import {ActivatedRoute} from '../router_state';
|
import {ActivatedRoute} from '../router_state';
|
||||||
import {UrlTree} from '../url_tree';
|
import {UrlTree} from '../url_tree';
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,10 @@
|
||||||
|
|
||||||
import {AfterContentInit, ChangeDetectorRef, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer, SimpleChanges} from '@angular/core';
|
import {AfterContentInit, ChangeDetectorRef, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer, SimpleChanges} from '@angular/core';
|
||||||
import {Subscription} from 'rxjs/Subscription';
|
import {Subscription} from 'rxjs/Subscription';
|
||||||
|
import {NavigationEnd} from '../events';
|
||||||
import {NavigationEnd, Router} from '../router';
|
import {Router} from '../router';
|
||||||
|
|
||||||
import {RouterLink, RouterLinkWithHref} from './router_link';
|
import {RouterLink, RouterLinkWithHref} from './router_link';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Lets you add a CSS class to an element when the link's route becomes active.
|
* @whatItDoes Lets you add a CSS class to an element when the link's route becomes active.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Attribute, ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
|
import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
|
||||||
|
|
||||||
import {RouterOutletMap} from '../router_outlet_map';
|
import {RouterOutletMap} from '../router_outlet_map';
|
||||||
import {ActivatedRoute} from '../router_state';
|
import {ActivatedRoute} from '../router_state';
|
||||||
import {PRIMARY_OUTLET} from '../shared';
|
import {PRIMARY_OUTLET} from '../shared';
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Route} from './config';
|
||||||
|
import {RouterStateSnapshot} from './router_state';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents an event triggered when a navigation starts.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export class NavigationStart {
|
||||||
|
// TODO: vsavkin: make internal
|
||||||
|
constructor(
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public id: number,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public url: string) {}
|
||||||
|
|
||||||
|
/** @docsNotRequired */
|
||||||
|
toString(): string { return `NavigationStart(id: ${this.id}, url: '${this.url}')`; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents an event triggered when a navigation ends successfully.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export class NavigationEnd {
|
||||||
|
// TODO: vsavkin: make internal
|
||||||
|
constructor(
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public id: number,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public url: string,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public urlAfterRedirects: string) {}
|
||||||
|
|
||||||
|
/** @docsNotRequired */
|
||||||
|
toString(): string {
|
||||||
|
return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents an event triggered when a navigation is canceled.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export class NavigationCancel {
|
||||||
|
// TODO: vsavkin: make internal
|
||||||
|
constructor(
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public id: number,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public url: string,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public reason: string) {}
|
||||||
|
|
||||||
|
/** @docsNotRequired */
|
||||||
|
toString(): string { return `NavigationCancel(id: ${this.id}, url: '${this.url}')`; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents an event triggered when a navigation fails due to an unexpected error.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export class NavigationError {
|
||||||
|
// TODO: vsavkin: make internal
|
||||||
|
constructor(
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public id: number,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public url: string,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public error: any) {}
|
||||||
|
|
||||||
|
/** @docsNotRequired */
|
||||||
|
toString(): string {
|
||||||
|
return `NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents an event triggered when routes are recognized.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export class RoutesRecognized {
|
||||||
|
// TODO: vsavkin: make internal
|
||||||
|
constructor(
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public id: number,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public url: string,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public urlAfterRedirects: string,
|
||||||
|
/** @docsNotRequired */
|
||||||
|
public state: RouterStateSnapshot) {}
|
||||||
|
|
||||||
|
/** @docsNotRequired */
|
||||||
|
toString(): string {
|
||||||
|
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents an event triggered when route is lazy loaded.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export class RouteConfigLoaded {
|
||||||
|
constructor(public route: Route) {}
|
||||||
|
|
||||||
|
toString(): string { return `RouteConfigLoaded(path: ${this.route.path})`; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @whatItDoes Represents a router event.
|
||||||
|
*
|
||||||
|
* Please see {@link NavigationStart}, {@link NavigationEnd}, {@link NavigationCancel}, {@link
|
||||||
|
* NavigationError}, {@link RoutesRecognized}, {@link RouteConfigLoaded} for more information.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError |
|
||||||
|
RoutesRecognized | RouteConfigLoaded;
|
|
@ -11,9 +11,9 @@ export {Data, LoadChildren, LoadChildrenCallback, ResolveData, Route, Routes} fr
|
||||||
export {RouterLink, RouterLinkWithHref} from './directives/router_link';
|
export {RouterLink, RouterLinkWithHref} from './directives/router_link';
|
||||||
export {RouterLinkActive} from './directives/router_link_active';
|
export {RouterLinkActive} from './directives/router_link_active';
|
||||||
export {RouterOutlet} from './directives/router_outlet';
|
export {RouterOutlet} from './directives/router_outlet';
|
||||||
|
export {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, RouteConfigLoaded, RoutesRecognized} from './events';
|
||||||
export {CanActivate, CanActivateChild, CanDeactivate, CanLoad, Resolve} from './interfaces';
|
export {CanActivate, CanActivateChild, CanDeactivate, CanLoad, Resolve} from './interfaces';
|
||||||
export {DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
|
export {DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
|
||||||
export {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationExtras, NavigationStart, Router, RoutesRecognized} from './router';
|
|
||||||
export {ROUTES} from './router_config_loader';
|
export {ROUTES} from './router_config_loader';
|
||||||
export {ExtraOptions, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule, provideRoutes} from './router_module';
|
export {ExtraOptions, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule, provideRoutes} from './router_module';
|
||||||
export {RouterOutletMap} from './router_outlet_map';
|
export {RouterOutletMap} from './router_outlet_map';
|
||||||
|
|
|
@ -22,10 +22,11 @@ import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||||
import {reduce} from 'rxjs/operator/reduce';
|
import {reduce} from 'rxjs/operator/reduce';
|
||||||
|
|
||||||
import {applyRedirects} from './apply_redirects';
|
import {applyRedirects} from './apply_redirects';
|
||||||
import {QueryParamsHandling, ResolveData, Routes, validateConfig} from './config';
|
import {QueryParamsHandling, ResolveData, Route, Routes, validateConfig} from './config';
|
||||||
import {createRouterState} from './create_router_state';
|
import {createRouterState} from './create_router_state';
|
||||||
import {createUrlTree} from './create_url_tree';
|
import {createUrlTree} from './create_url_tree';
|
||||||
import {RouterOutlet} from './directives/router_outlet';
|
import {RouterOutlet} from './directives/router_outlet';
|
||||||
|
import {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, RouteConfigLoaded, RoutesRecognized} from './events';
|
||||||
import {recognize} from './recognize';
|
import {recognize} from './recognize';
|
||||||
import {DetachedRouteHandle, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy';
|
import {DetachedRouteHandle, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy';
|
||||||
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
||||||
|
@ -151,119 +152,6 @@ export interface NavigationExtras {
|
||||||
replaceUrl?: boolean;
|
replaceUrl?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @whatItDoes Represents an event triggered when a navigation starts.
|
|
||||||
*
|
|
||||||
* @stable
|
|
||||||
*/
|
|
||||||
export class NavigationStart {
|
|
||||||
// TODO: vsavkin: make internal
|
|
||||||
constructor(
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public id: number,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public url: string) {}
|
|
||||||
|
|
||||||
/** @docsNotRequired */
|
|
||||||
toString(): string { return `NavigationStart(id: ${this.id}, url: '${this.url}')`; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @whatItDoes Represents an event triggered when a navigation ends successfully.
|
|
||||||
*
|
|
||||||
* @stable
|
|
||||||
*/
|
|
||||||
export class NavigationEnd {
|
|
||||||
// TODO: vsavkin: make internal
|
|
||||||
constructor(
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public id: number,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public url: string,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public urlAfterRedirects: string) {}
|
|
||||||
|
|
||||||
/** @docsNotRequired */
|
|
||||||
toString(): string {
|
|
||||||
return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @whatItDoes Represents an event triggered when a navigation is canceled.
|
|
||||||
*
|
|
||||||
* @stable
|
|
||||||
*/
|
|
||||||
export class NavigationCancel {
|
|
||||||
// TODO: vsavkin: make internal
|
|
||||||
constructor(
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public id: number,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public url: string,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public reason: string) {}
|
|
||||||
|
|
||||||
/** @docsNotRequired */
|
|
||||||
toString(): string { return `NavigationCancel(id: ${this.id}, url: '${this.url}')`; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @whatItDoes Represents an event triggered when a navigation fails due to an unexpected error.
|
|
||||||
*
|
|
||||||
* @stable
|
|
||||||
*/
|
|
||||||
export class NavigationError {
|
|
||||||
// TODO: vsavkin: make internal
|
|
||||||
constructor(
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public id: number,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public url: string,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public error: any) {}
|
|
||||||
|
|
||||||
/** @docsNotRequired */
|
|
||||||
toString(): string {
|
|
||||||
return `NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @whatItDoes Represents an event triggered when routes are recognized.
|
|
||||||
*
|
|
||||||
* @stable
|
|
||||||
*/
|
|
||||||
export class RoutesRecognized {
|
|
||||||
// TODO: vsavkin: make internal
|
|
||||||
constructor(
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public id: number,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public url: string,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public urlAfterRedirects: string,
|
|
||||||
/** @docsNotRequired */
|
|
||||||
public state: RouterStateSnapshot) {}
|
|
||||||
|
|
||||||
/** @docsNotRequired */
|
|
||||||
toString(): string {
|
|
||||||
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @whatItDoes Represents a router event.
|
|
||||||
*
|
|
||||||
* Please see {@link NavigationStart}, {@link NavigationEnd}, {@link NavigationCancel}, {@link
|
|
||||||
* NavigationError},
|
|
||||||
* {@link RoutesRecognized} for more information.
|
|
||||||
*
|
|
||||||
* @stable
|
|
||||||
*/
|
|
||||||
export type Event =
|
|
||||||
NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Error handler that is invoked when a navigation errors.
|
* @whatItDoes Error handler that is invoked when a navigation errors.
|
||||||
*
|
*
|
||||||
|
@ -320,7 +208,8 @@ export class Router {
|
||||||
private rawUrlTree: UrlTree;
|
private rawUrlTree: UrlTree;
|
||||||
|
|
||||||
private navigations = new BehaviorSubject<NavigationParams>(null);
|
private navigations = new BehaviorSubject<NavigationParams>(null);
|
||||||
private routerEvents = new Subject<Event>();
|
/** @internal */
|
||||||
|
routerEvents = new Subject<Event>();
|
||||||
|
|
||||||
private currentRouterState: RouterState;
|
private currentRouterState: RouterState;
|
||||||
private locationSubscription: Subscription;
|
private locationSubscription: Subscription;
|
||||||
|
@ -357,7 +246,8 @@ export class Router {
|
||||||
this.resetConfig(config);
|
this.resetConfig(config);
|
||||||
this.currentUrlTree = createEmptyUrlTree();
|
this.currentUrlTree = createEmptyUrlTree();
|
||||||
this.rawUrlTree = this.currentUrlTree;
|
this.rawUrlTree = this.currentUrlTree;
|
||||||
this.configLoader = new RouterConfigLoader(loader, compiler);
|
this.configLoader = new RouterConfigLoader(
|
||||||
|
loader, compiler, (r: Route) => this.routerEvents.next(new RouteConfigLoaded(r)));
|
||||||
this.currentRouterState = createEmptyState(this.currentUrlTree, this.rootComponentType);
|
this.currentRouterState = createEmptyState(this.currentUrlTree, this.rootComponentType);
|
||||||
this.processNavigations();
|
this.processNavigations();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,9 @@ import {fromPromise} from 'rxjs/observable/fromPromise';
|
||||||
import {of } from 'rxjs/observable/of';
|
import {of } from 'rxjs/observable/of';
|
||||||
import {map} from 'rxjs/operator/map';
|
import {map} from 'rxjs/operator/map';
|
||||||
import {mergeMap} from 'rxjs/operator/mergeMap';
|
import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||||
|
|
||||||
import {LoadChildren, Route} from './config';
|
import {LoadChildren, Route} from './config';
|
||||||
import {flatten, wrapIntoObservable} from './utils/collection';
|
import {flatten, wrapIntoObservable} from './utils/collection';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docsNotRequired
|
* @docsNotRequired
|
||||||
* @experimental
|
* @experimental
|
||||||
|
@ -30,14 +28,18 @@ export class LoadedRouterConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RouterConfigLoader {
|
export class RouterConfigLoader {
|
||||||
constructor(private loader: NgModuleFactoryLoader, private compiler: Compiler) {}
|
constructor(
|
||||||
|
private loader: NgModuleFactoryLoader, private compiler: Compiler,
|
||||||
|
private onLoadListener: (r: Route) => void) {}
|
||||||
|
|
||||||
load(parentInjector: Injector, loadChildren: LoadChildren): Observable<LoadedRouterConfig> {
|
load(parentInjector: Injector, route: Route): Observable<LoadedRouterConfig> {
|
||||||
return map.call(this.loadModuleFactory(loadChildren), (r: NgModuleFactory<any>) => {
|
const moduleFactory$ = this.loadModuleFactory(route.loadChildren);
|
||||||
const ref = r.create(parentInjector);
|
return map.call(moduleFactory$, (factory: NgModuleFactory<any>) => {
|
||||||
const injectorFactory = (parent: Injector) => r.create(parent).injector;
|
const module = factory.create(parentInjector);
|
||||||
|
const injectorFactory = (parent: Injector) => factory.create(parent).injector;
|
||||||
|
this.onLoadListener(route);
|
||||||
return new LoadedRouterConfig(
|
return new LoadedRouterConfig(
|
||||||
flatten(ref.injector.get(ROUTES)), ref.injector, ref.componentFactoryResolver,
|
flatten(module.injector.get(ROUTES)), module.injector, module.componentFactoryResolver,
|
||||||
injectorFactory);
|
injectorFactory);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@ import {concatMap} from 'rxjs/operator/concatMap';
|
||||||
import {filter} from 'rxjs/operator/filter';
|
import {filter} from 'rxjs/operator/filter';
|
||||||
import {mergeAll} from 'rxjs/operator/mergeAll';
|
import {mergeAll} from 'rxjs/operator/mergeAll';
|
||||||
import {mergeMap} from 'rxjs/operator/mergeMap';
|
import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||||
|
|
||||||
import {Route, Routes} from './config';
|
import {Route, Routes} from './config';
|
||||||
import {NavigationEnd, Router} from './router';
|
import {NavigationEnd, RouteConfigLoaded} from './events';
|
||||||
|
import {Router} from './router';
|
||||||
import {RouterConfigLoader} from './router_config_loader';
|
import {RouterConfigLoader} from './router_config_loader';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,17 +80,18 @@ export class RouterPreloader {
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router, moduleLoader: NgModuleFactoryLoader, compiler: Compiler,
|
private router: Router, moduleLoader: NgModuleFactoryLoader, compiler: Compiler,
|
||||||
private injector: Injector, private preloadingStrategy: PreloadingStrategy) {
|
private injector: Injector, private preloadingStrategy: PreloadingStrategy) {
|
||||||
this.loader = new RouterConfigLoader(moduleLoader, compiler);
|
this.loader = new RouterConfigLoader(
|
||||||
|
moduleLoader, compiler, (r: Route) => router.routerEvents.next(new RouteConfigLoaded(r)));
|
||||||
};
|
};
|
||||||
|
|
||||||
setUpPreloading(): void {
|
setUpPreloading(): void {
|
||||||
const navigations = filter.call(this.router.events, (e: any) => e instanceof NavigationEnd);
|
const navigations = filter.call(this.router.events, (e: any) => e instanceof NavigationEnd);
|
||||||
this.subscription = concatMap.call(navigations, () => this.preload()).subscribe((v: any) => {});
|
this.subscription = concatMap.call(navigations, () => this.preload()).subscribe(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
preload(): Observable<any> { return this.processRoutes(this.injector, this.router.config); }
|
preload(): Observable<any> { return this.processRoutes(this.injector, this.router.config); }
|
||||||
|
|
||||||
ngOnDestroy() { this.subscription.unsubscribe(); }
|
ngOnDestroy(): void { this.subscription.unsubscribe(); }
|
||||||
|
|
||||||
private processRoutes(injector: Injector, routes: Routes): Observable<void> {
|
private processRoutes(injector: Injector, routes: Routes): Observable<void> {
|
||||||
const res: Observable<any>[] = [];
|
const res: Observable<any>[] = [];
|
||||||
|
@ -114,7 +115,7 @@ export class RouterPreloader {
|
||||||
|
|
||||||
private preloadConfig(injector: Injector, route: Route): Observable<void> {
|
private preloadConfig(injector: Injector, route: Route): Observable<void> {
|
||||||
return this.preloadingStrategy.preload(route, () => {
|
return this.preloadingStrategy.preload(route, () => {
|
||||||
const loaded = this.loader.load(injector, route.loadChildren);
|
const loaded = this.loader.load(injector, route);
|
||||||
return mergeMap.call(loaded, (config: any): any => {
|
return mergeMap.call(loaded, (config: any): any => {
|
||||||
const c: any = route;
|
const c: any = route;
|
||||||
c._loadedConfig = config;
|
c._loadedConfig = config;
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {map} from 'rxjs/operator/map';
|
import {map} from 'rxjs/operator/map';
|
||||||
|
|
||||||
import {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, DetachedRouteHandle, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, Params, PreloadAllModules, PreloadingStrategy, Resolve, RouteReuseStrategy, Router, RouterModule, RouterStateSnapshot, RoutesRecognized, UrlHandlingStrategy, UrlSegmentGroup, UrlTree} from '../index';
|
import {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, DetachedRouteHandle, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, Params, PreloadAllModules, PreloadingStrategy, Resolve, RouteConfigLoaded, RouteReuseStrategy, Router, RouterModule, RouterStateSnapshot, RoutesRecognized, UrlHandlingStrategy, UrlSegmentGroup, UrlTree} from '../index';
|
||||||
import {RouterPreloader} from '../src/router_preloader';
|
import {RouterPreloader} from '../src/router_preloader';
|
||||||
import {forEach} from '../src/utils/collection';
|
import {forEach} from '../src/utils/collection';
|
||||||
import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing';
|
import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing';
|
||||||
|
@ -2011,8 +2011,8 @@ describe('Integration', () => {
|
||||||
expect(location.path()).toEqual('/lazyTrue/loaded');
|
expect(location.path()).toEqual('/lazyTrue/loaded');
|
||||||
|
|
||||||
expectEvents(recordedEvents, [
|
expectEvents(recordedEvents, [
|
||||||
[NavigationStart, '/lazyTrue/loaded'], [RoutesRecognized, '/lazyTrue/loaded'],
|
[NavigationStart, '/lazyTrue/loaded'], [RouteConfigLoaded, undefined],
|
||||||
[NavigationEnd, '/lazyTrue/loaded']
|
[RoutesRecognized, '/lazyTrue/loaded'], [NavigationEnd, '/lazyTrue/loaded']
|
||||||
]);
|
]);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
@ -2299,6 +2299,51 @@ describe('Integration', () => {
|
||||||
expect(fixture.nativeElement).toHaveText('lazy-loaded-parent [lazy-loaded-child]');
|
expect(fixture.nativeElement).toHaveText('lazy-loaded-parent [lazy-loaded-child]');
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
it('should emit RouteConfigLoaded event when route is lazy loaded',
|
||||||
|
fakeAsync(inject(
|
||||||
|
[Router, Location, NgModuleFactoryLoader],
|
||||||
|
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
|
||||||
|
@Component({
|
||||||
|
selector: 'lazy',
|
||||||
|
template: 'lazy-loaded-parent [<router-outlet></router-outlet>]'
|
||||||
|
})
|
||||||
|
class ParentLazyLoadedComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'lazy', template: 'lazy-loaded-child'})
|
||||||
|
class ChildLazyLoadedComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [ParentLazyLoadedComponent, ChildLazyLoadedComponent],
|
||||||
|
imports: [RouterModule.forChild([{
|
||||||
|
path: 'loaded',
|
||||||
|
component: ParentLazyLoadedComponent,
|
||||||
|
children: [{path: 'child', component: ChildLazyLoadedComponent}]
|
||||||
|
}])]
|
||||||
|
})
|
||||||
|
class LoadedModule {
|
||||||
|
}
|
||||||
|
|
||||||
|
const events: RouteConfigLoaded[] = [];
|
||||||
|
|
||||||
|
router.events.subscribe(e => {
|
||||||
|
if (e instanceof RouteConfigLoaded) {
|
||||||
|
events.push(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.stubbedModules = {expected: LoadedModule};
|
||||||
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]);
|
||||||
|
|
||||||
|
router.navigateByUrl('/lazy/loaded/child');
|
||||||
|
advance(fixture);
|
||||||
|
|
||||||
|
expect(events.length).toEqual(1);
|
||||||
|
expect(events[0].route.path).toEqual('lazy');
|
||||||
|
})));
|
||||||
|
|
||||||
it('throws an error when forRoot() is used in a lazy context',
|
it('throws an error when forRoot() is used in a lazy context',
|
||||||
fakeAsync(inject(
|
fakeAsync(inject(
|
||||||
[Router, Location, NgModuleFactoryLoader],
|
[Router, Location, NgModuleFactoryLoader],
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {Component, NgModule, NgModuleFactoryLoader} from '@angular/core';
|
import {Component, NgModule, NgModuleFactoryLoader} from '@angular/core';
|
||||||
import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing';
|
import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing';
|
||||||
|
|
||||||
import {Router, RouterModule} from '../index';
|
import {RouteConfigLoaded, Router, RouterModule} from '../index';
|
||||||
import {PreloadAllModules, PreloadingStrategy, RouterPreloader} from '../src/router_preloader';
|
import {PreloadAllModules, PreloadingStrategy, RouterPreloader} from '../src/router_preloader';
|
||||||
import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing';
|
import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing';
|
||||||
|
|
||||||
|
@ -46,6 +46,12 @@ describe('RouterPreloader', () => {
|
||||||
fakeAsync(inject(
|
fakeAsync(inject(
|
||||||
[NgModuleFactoryLoader, RouterPreloader, Router],
|
[NgModuleFactoryLoader, RouterPreloader, Router],
|
||||||
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
|
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router) => {
|
||||||
|
const events: RouteConfigLoaded[] = [];
|
||||||
|
router.events.subscribe(e => {
|
||||||
|
if (e instanceof RouteConfigLoaded) {
|
||||||
|
events.push(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
loader.stubbedModules = {expected: LoadedModule1, expected2: LoadedModule2};
|
loader.stubbedModules = {expected: LoadedModule1, expected2: LoadedModule2};
|
||||||
|
|
||||||
preloader.preload().subscribe(() => {});
|
preloader.preload().subscribe(() => {});
|
||||||
|
@ -60,6 +66,9 @@ describe('RouterPreloader', () => {
|
||||||
|
|
||||||
const loaded2: any = (<any>loaded[0])._loadedConfig.routes;
|
const loaded2: any = (<any>loaded[0])._loadedConfig.routes;
|
||||||
expect(loaded2[0].path).toEqual('LoadedModule2');
|
expect(loaded2[0].path).toEqual('LoadedModule2');
|
||||||
|
expect(events.length).toEqual(2);
|
||||||
|
expect(events[0].route.path).toEqual('lazy');
|
||||||
|
expect(events[1].route.path).toEqual('LoadedModule1');
|
||||||
})));
|
})));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ export declare class DefaultUrlSerializer implements UrlSerializer {
|
||||||
export declare type DetachedRouteHandle = {};
|
export declare type DetachedRouteHandle = {};
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized;
|
export declare type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized | RouteConfigLoaded;
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export interface ExtraOptions {
|
export interface ExtraOptions {
|
||||||
|
@ -199,6 +199,13 @@ export interface Route {
|
||||||
resolve?: ResolveData;
|
resolve?: ResolveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @experimental */
|
||||||
|
export declare class RouteConfigLoaded {
|
||||||
|
route: Route;
|
||||||
|
constructor(route: Route);
|
||||||
|
toString(): string;
|
||||||
|
}
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class Router {
|
export declare class Router {
|
||||||
config: Routes;
|
config: Routes;
|
||||||
|
|
Loading…
Reference in New Issue