From 29caa379438e485a93dd66ce9e4177851a5d5dfc Mon Sep 17 00:00:00 2001 From: vsavkin Date: Tue, 2 Aug 2016 13:27:55 -0700 Subject: [PATCH] feat(router): support sibling modules providing routes --- .../router/src/common_router_providers.ts | 10 ++-- .../router/src/router_config_loader.ts | 4 +- modules/@angular/router/test/router.spec.ts | 51 +++++++++++++++++++ .../router/testing/router_testing_module.ts | 8 +-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/modules/@angular/router/src/common_router_providers.ts b/modules/@angular/router/src/common_router_providers.ts index e41ec965cb..e6171ce902 100644 --- a/modules/@angular/router/src/common_router_providers.ts +++ b/modules/@angular/router/src/common_router_providers.ts @@ -9,12 +9,13 @@ 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 {Routes} from './config'; +import {Route, Routes} from './config'; import {Router} from './router'; import {ROUTER_CONFIG, ROUTES} from './router_config_loader'; import {RouterOutletMap} from './router_outlet_map'; import {ActivatedRoute} from './router_state'; import {DefaultUrlSerializer, UrlSerializer} from './url_tree'; +import {flatten} from './utils/collection'; export const ROUTER_CONFIGURATION = new OpaqueToken('ROUTER_CONFIGURATION'); @@ -29,13 +30,14 @@ export interface ExtraOptions { export function setupRouter( ref: ApplicationRef, resolver: ComponentResolver, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, injector: Injector, - loader: NgModuleFactoryLoader, config: Routes, opts: ExtraOptions = {}) { + loader: NgModuleFactoryLoader, config: Route[][], opts: ExtraOptions = {}) { if (ref.componentTypes.length == 0) { throw new Error('Bootstrap at least one component before injecting Router.'); } const componentType = ref.componentTypes[0]; const r = new Router( - componentType, resolver, urlSerializer, outletMap, location, injector, loader, config); + componentType, resolver, urlSerializer, outletMap, location, injector, loader, + flatten(config)); if (opts.enableTracing) { r.events.subscribe(e => { @@ -130,7 +132,7 @@ export function provideRouterInitializer() { export function provideRoutes(routes: Routes): any { return [ {provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes}, - {provide: ROUTES, useValue: routes} + {provide: ROUTES, multi: true, useValue: routes} ]; } diff --git a/modules/@angular/router/src/router_config_loader.ts b/modules/@angular/router/src/router_config_loader.ts index 5f73d112a3..a3ef2f475a 100644 --- a/modules/@angular/router/src/router_config_loader.ts +++ b/modules/@angular/router/src/router_config_loader.ts @@ -11,7 +11,7 @@ import {Observable} from 'rxjs/Observable'; import {fromPromise} from 'rxjs/observable/fromPromise'; import {Route} from './config'; - +import {flatten} from './utils/collection'; /** @@ -33,7 +33,7 @@ export class RouterConfigLoader { return fromPromise(this.loader.load(path).then(r => { const ref = r.create(parentInjector); return new LoadedRouterConfig( - ref.injector.get(ROUTES), ref.injector, ref.componentFactoryResolver); + flatten(ref.injector.get(ROUTES)), ref.injector, ref.componentFactoryResolver); })); } } diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index 2f5b1c774e..2fb29c3e98 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -1445,6 +1445,57 @@ describe('Integration', () => { .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', fakeAsync(inject( [Router, TestComponentBuilder, Location, NgModuleFactoryLoader], diff --git a/modules/@angular/router/testing/router_testing_module.ts b/modules/@angular/router/testing/router_testing_module.ts index d06561cb59..e3c0346108 100644 --- a/modules/@angular/router/testing/router_testing_module.ts +++ b/modules/@angular/router/testing/router_testing_module.ts @@ -10,9 +10,10 @@ import {Location, LocationStrategy} from '@angular/common'; import {MockLocationStrategy, SpyLocation} from '@angular/common/testing'; 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 {ROUTER_PROVIDERS, RouterModule} from '../src/router_module'; +import {flatten} from '../src/utils/collection'; @@ -39,8 +40,9 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader { function setupTestingRouter( resolver: ComponentResolver, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, - location: Location, loader: NgModuleFactoryLoader, injector: Injector, routes: Routes) { - return new Router(null, resolver, urlSerializer, outletMap, location, injector, loader, routes); + location: Location, loader: NgModuleFactoryLoader, injector: Injector, routes: Route[][]) { + return new Router( + null, resolver, urlSerializer, outletMap, location, injector, loader, flatten(routes)); } /**