From 2a4bf9a0df61ac515155954c88ca5af9c4314c68 Mon Sep 17 00:00:00 2001 From: Michael Seemann Date: Sun, 16 Oct 2016 20:33:50 +0200 Subject: [PATCH] fix(router): avoid router initialization for non root components closes #12338 closes #12814 --- modules/@angular/router/src/router_module.ts | 10 +- .../router/test/router_module.spec.ts | 91 +++++++++++++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 modules/@angular/router/test/router_module.spec.ts diff --git a/modules/@angular/router/src/router_module.ts b/modules/@angular/router/src/router_module.ts index d4ae762ffe..36d83c22c5 100644 --- a/modules/@angular/router/src/router_module.ts +++ b/modules/@angular/router/src/router_module.ts @@ -7,8 +7,7 @@ */ import {APP_BASE_HREF, HashLocationStrategy, Location, LocationStrategy, PathLocationStrategy, PlatformLocation} from '@angular/common'; -import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, ApplicationRef, Compiler, Inject, Injector, ModuleWithProviders, NgModule, NgModuleFactoryLoader, OpaqueToken, Optional, Provider, SkipSelf, SystemJsNgModuleLoader} from '@angular/core'; - +import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, ApplicationRef, Compiler, ComponentRef, Inject, Injector, ModuleWithProviders, NgModule, NgModuleFactoryLoader, OpaqueToken, Optional, Provider, SkipSelf, SystemJsNgModuleLoader} from '@angular/core'; import {Route, Routes} from './config'; import {RouterLink, RouterLinkWithHref} from './directives/router_link'; import {RouterLinkActive} from './directives/router_link_active'; @@ -268,7 +267,12 @@ export function rootRoute(router: Router): ActivatedRoute { export function initialRouterNavigation( router: Router, ref: ApplicationRef, preloader: RouterPreloader, opts: ExtraOptions) { - return () => { + return (bootstrappedComponentRef: ComponentRef) => { + + if (bootstrappedComponentRef !== ref.components[0]) { + return; + } + router.resetRootComponentType(ref.componentTypes[0]); preloader.setUpPreloading(); if (opts.initialNavigation === false) { diff --git a/modules/@angular/router/test/router_module.spec.ts b/modules/@angular/router/test/router_module.spec.ts new file mode 100644 index 0000000000..379a3a35d7 --- /dev/null +++ b/modules/@angular/router/test/router_module.spec.ts @@ -0,0 +1,91 @@ +/** + * @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 {APP_BASE_HREF} from '@angular/common'; +import {ApplicationRef, Component, NgModule} from '@angular/core'; +import {TestBed, inject} from '@angular/core/testing'; +import {DOCUMENT} from '@angular/platform-browser'; +import {Router, RouterModule, Routes} from '@angular/router'; + + +@Component({selector: 'app-root', template: ''}) +export class AppRootComponent { +} + +@Component({selector: 'bootstrappable-component', template: ''}) +export class BootstrappableComponent { +} + +export const appRoutes: Routes = [{path: '**', redirectTo: ''}]; + + +@NgModule({ + imports: [RouterModule.forRoot(appRoutes)], + declarations: [AppRootComponent, BootstrappableComponent], + entryComponents: [AppRootComponent, BootstrappableComponent], + providers: [{provide: APP_BASE_HREF, useValue: '/'}] +}) +export class RouterInitTestModule { +} + + +describe('RouterModule', () => { + describe('RouterInitializer', () => { + + beforeEach(() => { TestBed.configureTestingModule({imports: [RouterInitTestModule]}); }); + + beforeEach(inject([DOCUMENT], function(doc: HTMLDocument) { + + const elRootApp = doc.createElement('app-root'); + doc.body.appendChild(elRootApp); + + const elBootComp = doc.createElement('bootstrappable-component'); + doc.body.appendChild(elBootComp); + + })); + it('should not init router navigation listeners if a non root component is bootstrapped', + () => { + + const appRef: ApplicationRef = TestBed.get(ApplicationRef); + const r: Router = TestBed.get(Router); + + const spy = spyOn(r, 'resetRootComponentType').and.callThrough(); + + appRef.bootstrap(AppRootComponent); + expect(r.resetRootComponentType).toHaveBeenCalled(); + + spy.calls.reset(); + + appRef.bootstrap(BootstrappableComponent); + expect(r.resetRootComponentType).not.toHaveBeenCalled(); + }); + it('should reinit router navigation listeners if a previously bootstrapped root component is destroyed', + (done) => { + + const appRef: ApplicationRef = TestBed.get(ApplicationRef); + const r: Router = TestBed.get(Router); + + const spy = spyOn(r, 'resetRootComponentType').and.callThrough(); + + const compRef = appRef.bootstrap(AppRootComponent); + expect(r.resetRootComponentType).toHaveBeenCalled(); + + spy.calls.reset(); + + compRef.onDestroy(() => { + + appRef.bootstrap(BootstrappableComponent); + expect(r.resetRootComponentType).toHaveBeenCalled(); + + done(); + }); + + compRef.destroy(); + }); + }); + +});