feat(router): support sibling modules providing routes

This commit is contained in:
vsavkin 2016-08-02 13:27:55 -07:00
parent 8efbcc996a
commit 29caa37943
4 changed files with 64 additions and 9 deletions

View File

@ -9,12 +9,13 @@
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common'; import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, ApplicationRef, ComponentResolver, Injector, NgModuleFactoryLoader, OpaqueToken, SystemJsNgModuleLoader} from '@angular/core'; import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, ApplicationRef, ComponentResolver, Injector, NgModuleFactoryLoader, OpaqueToken, SystemJsNgModuleLoader} from '@angular/core';
import {Routes} from './config'; import {Route, Routes} from './config';
import {Router} from './router'; import {Router} from './router';
import {ROUTER_CONFIG, ROUTES} from './router_config_loader'; import {ROUTER_CONFIG, ROUTES} from './router_config_loader';
import {RouterOutletMap} from './router_outlet_map'; import {RouterOutletMap} from './router_outlet_map';
import {ActivatedRoute} from './router_state'; import {ActivatedRoute} from './router_state';
import {DefaultUrlSerializer, UrlSerializer} from './url_tree'; import {DefaultUrlSerializer, UrlSerializer} from './url_tree';
import {flatten} from './utils/collection';
export const ROUTER_CONFIGURATION = new OpaqueToken('ROUTER_CONFIGURATION'); export const ROUTER_CONFIGURATION = new OpaqueToken('ROUTER_CONFIGURATION');
@ -29,13 +30,14 @@ export interface ExtraOptions {
export function setupRouter( export function setupRouter(
ref: ApplicationRef, resolver: ComponentResolver, urlSerializer: UrlSerializer, ref: ApplicationRef, resolver: ComponentResolver, urlSerializer: UrlSerializer,
outletMap: RouterOutletMap, location: Location, injector: Injector, outletMap: RouterOutletMap, location: Location, injector: Injector,
loader: NgModuleFactoryLoader, config: Routes, opts: ExtraOptions = {}) { loader: NgModuleFactoryLoader, config: Route[][], opts: ExtraOptions = {}) {
if (ref.componentTypes.length == 0) { if (ref.componentTypes.length == 0) {
throw new Error('Bootstrap at least one component before injecting Router.'); throw new Error('Bootstrap at least one component before injecting Router.');
} }
const componentType = ref.componentTypes[0]; const componentType = ref.componentTypes[0];
const r = new Router( const r = new Router(
componentType, resolver, urlSerializer, outletMap, location, injector, loader, config); componentType, resolver, urlSerializer, outletMap, location, injector, loader,
flatten(config));
if (opts.enableTracing) { if (opts.enableTracing) {
r.events.subscribe(e => { r.events.subscribe(e => {
@ -130,7 +132,7 @@ export function provideRouterInitializer() {
export function provideRoutes(routes: Routes): any { export function provideRoutes(routes: Routes): any {
return [ return [
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes}, {provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes},
{provide: ROUTES, useValue: routes} {provide: ROUTES, multi: true, useValue: routes}
]; ];
} }

View File

@ -11,7 +11,7 @@ import {Observable} from 'rxjs/Observable';
import {fromPromise} from 'rxjs/observable/fromPromise'; import {fromPromise} from 'rxjs/observable/fromPromise';
import {Route} from './config'; import {Route} from './config';
import {flatten} from './utils/collection';
/** /**
@ -33,7 +33,7 @@ export class RouterConfigLoader {
return fromPromise(this.loader.load(path).then(r => { return fromPromise(this.loader.load(path).then(r => {
const ref = r.create(parentInjector); const ref = r.create(parentInjector);
return new LoadedRouterConfig( return new LoadedRouterConfig(
ref.injector.get(ROUTES), ref.injector, ref.componentFactoryResolver); flatten(ref.injector.get(ROUTES)), ref.injector, ref.componentFactoryResolver);
})); }));
} }
} }

View File

@ -1445,6 +1445,57 @@ describe('Integration', () => {
.toHaveText('lazy-loaded-parent [lazy-loaded-child]'); .toHaveText('lazy-loaded-parent [lazy-loaded-child]');
}))); })));
it('should combine routes from multiple modules into a single configuration',
fakeAsync(inject(
[Router, TestComponentBuilder, Location, NgModuleFactoryLoader],
(router: Router, tcb: TestComponentBuilder, location: Location,
loader: SpyNgModuleFactoryLoader) => {
@Component({selector: 'lazy', template: 'lazy-loaded-2'})
class LazyComponent2 {
}
@NgModule({
declarations: [LazyComponent2],
imports: [RouterModule.forChild([{path: 'loaded', component: LazyComponent2}])],
entryComponents: [LazyComponent2]
})
class SiblingOfLoadedModule {
}
@Component(
{selector: 'lazy', template: 'lazy-loaded-1', directives: ROUTER_DIRECTIVES})
class LazyComponent1 {
}
@NgModule({
declarations: [LazyComponent1],
imports: [
RouterModule.forChild([{path: 'loaded', component: LazyComponent1}]),
SiblingOfLoadedModule
],
entryComponents: [LazyComponent1]
})
class LoadedModule {
}
loader.stubbedModules = {expected1: LoadedModule, expected2: SiblingOfLoadedModule};
const fixture = createRoot(tcb, router, RootCmp);
router.resetConfig([
{path: 'lazy1', loadChildren: 'expected1'},
{path: 'lazy2', loadChildren: 'expected2'}
]);
router.navigateByUrl('/lazy1/loaded');
advance(fixture);
expect(location.path()).toEqual('/lazy1/loaded');
router.navigateByUrl('/lazy2/loaded');
advance(fixture);
expect(location.path()).toEqual('/lazy2/loaded');
})));
it('should use the injector of the lazily-loaded configuration', it('should use the injector of the lazily-loaded configuration',
fakeAsync(inject( fakeAsync(inject(
[Router, TestComponentBuilder, Location, NgModuleFactoryLoader], [Router, TestComponentBuilder, Location, NgModuleFactoryLoader],

View File

@ -10,9 +10,10 @@ import {Location, LocationStrategy} from '@angular/common';
import {MockLocationStrategy, SpyLocation} from '@angular/common/testing'; import {MockLocationStrategy, SpyLocation} from '@angular/common/testing';
import {Compiler, ComponentResolver, Injectable, Injector, NgModule, NgModuleFactory, NgModuleFactoryLoader} from '@angular/core'; import {Compiler, ComponentResolver, Injectable, Injector, NgModule, NgModuleFactory, NgModuleFactoryLoader} from '@angular/core';
import {Router, RouterOutletMap, Routes, UrlSerializer} from '../index'; import {Route, Router, RouterOutletMap, UrlSerializer} from '../index';
import {ROUTES} from '../src/router_config_loader'; import {ROUTES} from '../src/router_config_loader';
import {ROUTER_PROVIDERS, RouterModule} from '../src/router_module'; import {ROUTER_PROVIDERS, RouterModule} from '../src/router_module';
import {flatten} from '../src/utils/collection';
@ -39,8 +40,9 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader {
function setupTestingRouter( function setupTestingRouter(
resolver: ComponentResolver, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, resolver: ComponentResolver, urlSerializer: UrlSerializer, outletMap: RouterOutletMap,
location: Location, loader: NgModuleFactoryLoader, injector: Injector, routes: Routes) { location: Location, loader: NgModuleFactoryLoader, injector: Injector, routes: Route[][]) {
return new Router(null, resolver, urlSerializer, outletMap, location, injector, loader, routes); return new Router(
null, resolver, urlSerializer, outletMap, location, injector, loader, flatten(routes));
} }
/** /**