From a80ecf6a7770decec565521022f73d6f6686d5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=A1ko=20Hevery?= Date: Tue, 22 Aug 2017 18:39:06 -0500 Subject: [PATCH] Revert "refactor(router): remove deprecated `initialNavigation` options (#18781)" This reverts commit d76761bf0136e03dd998e614f0ddd74393bd6332. --- .../examples/ngmodule/src/index.3.html | 2 +- packages/router/src/router_module.ts | 37 ++++++++-- packages/router/test/bootstrap.spec.ts | 73 +++++++++++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/aio/content/examples/ngmodule/src/index.3.html b/aio/content/examples/ngmodule/src/index.3.html index 43da9f2a37..ec55dd984e 100644 --- a/aio/content/examples/ngmodule/src/index.3.html +++ b/aio/content/examples/ngmodule/src/index.3.html @@ -1,7 +1,7 @@ - + NgModule - Contact diff --git a/packages/router/src/router_module.ts b/packages/router/src/router_module.ts index 78fa920ae2..8ecec6aff7 100644 --- a/packages/router/src/router_module.ts +++ b/packages/router/src/router_module.ts @@ -218,14 +218,24 @@ export function provideRoutes(routes: Routes): any { * The bootstrap is blocked until the initial navigation is complete. * * 'disabled' - the initial navigation is not performed. The location listener is set up before * the root component gets created. + * * 'legacy_enabled'- the initial navigation starts after the root component has been created. + * The bootstrap is not blocked until the initial navigation is complete. @deprecated + * * 'legacy_disabled'- the initial navigation is not performed. The location listener is set up + * after @deprecated + * the root component gets created. + * * `true` - same as 'legacy_enabled'. @deprecated since v4 + * * `false` - same as 'legacy_disabled'. @deprecated since v4 * * The 'enabled' option should be used for applications unless there is a reason to have * more control over when the router starts its initial navigation due to some complex * initialization logic. In this case, 'disabled' should be used. * + * The 'legacy_enabled' and 'legacy_disabled' should not be used for new applications. + * * @experimental */ -export type InitialNavigation = 'enabled' | 'disabled'; +export type InitialNavigation = + true | false | 'enabled' | 'disabled' | 'legacy_enabled' | 'legacy_disabled'; /** * @whatItDoes Represents options to configure the router. @@ -244,7 +254,7 @@ export interface ExtraOptions { useHash?: boolean; /** - * Enables/Disables the initial navigation (enabled by default). + * Disables the initial navigation. */ initialNavigation?: InitialNavigation; @@ -322,12 +332,14 @@ export class RouterInitializer { const router = this.injector.get(Router); const opts = this.injector.get(ROUTER_CONFIGURATION); - if (opts.initialNavigation === 'disabled') { + if (this.isLegacyDisabled(opts) || this.isLegacyEnabled(opts)) { + resolve(true); + + } else if (opts.initialNavigation === 'disabled') { router.setUpLocationChangeListener(); resolve(true); - } else if ( - opts.initialNavigation === 'enabled' || typeof opts.initialNavigation === 'undefined') { + } else if (opts.initialNavigation === 'enabled') { router.hooks.afterPreactivation = () => { // only the initial navigation should be delayed if (!this.initNavigation) { @@ -360,11 +372,26 @@ export class RouterInitializer { return; } + if (this.isLegacyEnabled(opts)) { + router.initialNavigation(); + } else if (this.isLegacyDisabled(opts)) { + router.setUpLocationChangeListener(); + } + preloader.setUpPreloading(); router.resetRootComponentType(ref.componentTypes[0]); this.resultOfPreactivationDone.next(null !); this.resultOfPreactivationDone.complete(); } + + private isLegacyEnabled(opts: ExtraOptions): boolean { + return opts.initialNavigation === 'legacy_enabled' || opts.initialNavigation === true || + opts.initialNavigation === undefined; + } + + private isLegacyDisabled(opts: ExtraOptions): boolean { + return opts.initialNavigation === 'legacy_disabled' || opts.initialNavigation === false; + } } export function getAppInitializer(r: RouterInitializer) { diff --git a/packages/router/test/bootstrap.spec.ts b/packages/router/test/bootstrap.spec.ts index 61d718e583..1277345b87 100644 --- a/packages/router/test/bootstrap.spec.ts +++ b/packages/router/test/bootstrap.spec.ts @@ -90,6 +90,48 @@ describe('bootstrap', () => { }); }); + it('should NOT wait for resolvers to complete when initialNavigation = legacy_enabled', + (done) => { + @Component({selector: 'test', template: 'test'}) + class TestCmpLegacyEnabled { + } + + @NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot( + [{path: '**', component: TestCmpLegacyEnabled, resolve: {test: TestResolver}}], + {useHash: true, initialNavigation: 'legacy_enabled'}) + ], + declarations: [RootCmp, TestCmpLegacyEnabled], + bootstrap: [RootCmp], + providers: [...testProviders, TestResolver], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + class TestModule { + constructor(router: Router) { + log.push('TestModule'); + router.events.subscribe(e => log.push(e.constructor.name)); + } + } + + platformBrowserDynamic([]).bootstrapModule(TestModule).then(res => { + const router = res.injector.get(Router); + expect(router.routerState.snapshot.root.firstChild).toBeNull(); + // ResolveEnd has not been emitted yet because bootstrap returned too early + expect(log).toEqual([ + 'TestModule', 'RootCmp', 'NavigationStart', 'RoutesRecognized', 'GuardsCheckStart', + 'GuardsCheckEnd', 'ResolveStart' + ]); + + router.events.subscribe((e) => { + if (e instanceof NavigationEnd) { + done(); + } + }); + }); + }); + it('should not run navigation when initialNavigation = disabled', (done) => { @Component({selector: 'test', template: 'test'}) class TestCmpDiabled { @@ -120,6 +162,37 @@ describe('bootstrap', () => { }); }); + it('should not run navigation when initialNavigation = legacy_disabled', (done) => { + @Component({selector: 'test', template: 'test'}) + class TestCmpLegacyDisabled { + } + + @NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot( + [{path: '**', component: TestCmpLegacyDisabled, resolve: {test: TestResolver}}], + {useHash: true, initialNavigation: 'legacy_disabled'}) + ], + declarations: [RootCmp, TestCmpLegacyDisabled], + bootstrap: [RootCmp], + providers: [...testProviders, TestResolver], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + class TestModule { + constructor(router: Router) { + log.push('TestModule'); + router.events.subscribe(e => log.push(e.constructor.name)); + } + } + + platformBrowserDynamic([]).bootstrapModule(TestModule).then(res => { + const router = res.injector.get(Router); + expect(log).toEqual(['TestModule', 'RootCmp']); + done(); + }); + }); + it('should not init router navigation listeners if a non root component is bootstrapped', (done) => { @NgModule({