feat(router): add support for lazily loaded modules

This commit is contained in:
vsavkin
2016-07-06 11:02:16 -07:00
parent 6fcf962fb5
commit 8ebb8e44c8
13 changed files with 431 additions and 140 deletions

View File

@ -15,24 +15,25 @@ import 'rxjs/add/observable/from';
import 'rxjs/add/observable/forkJoin';
import {Location} from '@angular/common';
import {ComponentResolver, Injector, ReflectiveInjector, Type} from '@angular/core';
import {AppModuleFactoryLoader, ComponentFactoryResolver, ComponentResolver, Injector, ReflectiveInjector, Type} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {Subscription} from 'rxjs/Subscription';
import {of } from 'rxjs/observable/of';
import {applyRedirects} from './apply_redirects';
import {Data, ResolveData, RouterConfig, validateConfig} from './config';
import {ResolveData, RouterConfig, validateConfig} from './config';
import {createRouterState} from './create_router_state';
import {createUrlTree} from './create_url_tree';
import {RouterOutlet} from './directives/router_outlet';
import {recognize} from './recognize';
import {resolve} from './resolve';
import {RouterConfigLoader} from './router_config_loader';
import {RouterOutletMap} from './router_outlet_map';
import {ActivatedRoute, ActivatedRouteSnapshot, InheritedResolve, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';
import {PRIMARY_OUTLET, Params} from './shared';
import {UrlSerializer, UrlTree, createEmptyUrlTree} from './url_tree';
import {forEach, merge, shallowEqual} from './utils/collection';
import {forEach, merge, shallowEqual, waitForMap} from './utils/collection';
import {TreeNode} from './utils/tree';
export interface NavigationExtras {
@ -124,6 +125,7 @@ export class Router {
private navigationId: number = 0;
private config: RouterConfig;
private futureUrlTree: UrlTree;
private configLoader: RouterConfigLoader;
/**
* Creates the router service.
@ -131,11 +133,13 @@ export class Router {
constructor(
private rootComponentType: Type, private resolver: ComponentResolver,
private urlSerializer: UrlSerializer, private outletMap: RouterOutletMap,
private location: Location, private injector: Injector, config: RouterConfig) {
private location: Location, private injector: Injector, loader: AppModuleFactoryLoader,
config: RouterConfig) {
this.resetConfig(config);
this.routerEvents = new Subject<Event>();
this.currentUrlTree = createEmptyUrlTree();
this.futureUrlTree = this.currentUrlTree;
this.configLoader = new RouterConfigLoader(loader);
this.currentRouterState = createEmptyState(this.currentUrlTree, this.rootComponentType);
}
@ -310,7 +314,7 @@ export class Router {
let state: RouterState;
let navigationIsSuccessful: boolean;
let preActivation: PreActivation;
applyRedirects(url, this.config)
applyRedirects(this.configLoader, url, this.config)
.mergeMap(u => {
this.futureUrlTree = u;
return recognize(
@ -555,20 +559,11 @@ class PreActivation {
}
private resolveNode(resolve: ResolveData, future: ActivatedRouteSnapshot): Observable<any> {
const resolvingObs: Observable<any>[] = [];
const resolvedData: {[k: string]: any} = {};
forEach(resolve, (v: any, k: string) => {
return waitForMap(resolve, (k, v) => {
const resolver = this.injector.get(v);
const obs = resolver.resolve ? wrapIntoObservable(resolver.resolve(future, this.future)) :
wrapIntoObservable(resolver(future, this.future));
resolvingObs.push(obs.map((_: any) => { resolvedData[k] = _; }));
return resolver.resolve ? wrapIntoObservable(resolver.resolve(future, this.future)) :
wrapIntoObservable(resolver(future, this.future));
});
if (resolvingObs.length > 0) {
return Observable.forkJoin(resolvingObs).map(r => resolvedData);
} else {
return of (resolvedData);
}
}
}
@ -656,11 +651,22 @@ class ActivateRoutes {
private placeComponentIntoOutlet(
outletMap: RouterOutletMap, future: ActivatedRoute, outlet: RouterOutlet): void {
const resolved = ReflectiveInjector.resolve([
{provide: ActivatedRoute, useValue: future},
{provide: RouterOutletMap, useValue: outletMap}
]);
outlet.activate(future, resolved, outletMap);
const resolved = <any[]>[{provide: ActivatedRoute, useValue: future}, {
provide: RouterOutletMap,
useValue: outletMap
}];
const parentFuture = this.futureState.parent(future); // find the closest parent?
const config = parentFuture ? parentFuture.snapshot._routeConfig : null;
let loadedFactoryResolver: ComponentFactoryResolver = null;
if (config && (<any>config)._loadedConfig) {
const loadedResolver = (<any>config)._loadedConfig.factoryResolver;
loadedFactoryResolver = loadedResolver;
resolved.push({provide: ComponentFactoryResolver, useValue: loadedResolver});
};
outlet.activate(future, loadedFactoryResolver, ReflectiveInjector.resolve(resolved), outletMap);
}
private deactivateOutletAndItChildren(outlet: RouterOutlet): void {