feat(router): throw a helpful error when misusing forRoot() from a lazy module. (#10996)

This commit is contained in:
Alex Rickabaugh 2016-08-23 11:57:58 -07:00 committed by Kara
parent c02325dd06
commit 5ddecb18a7
3 changed files with 46 additions and 2 deletions

View File

@ -7,7 +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, SystemJsNgModuleLoader} from '@angular/core';
import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, ApplicationRef, BaseException, Compiler, Inject, Injector, ModuleWithProviders, NgModule, NgModuleFactoryLoader, OpaqueToken, Optional, SkipSelf, SystemJsNgModuleLoader} from '@angular/core';
import {Route, Routes} from './config';
import {RouterLink, RouterLinkWithHref} from './directives/router_link';
@ -32,6 +32,8 @@ export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref,
*/
export const ROUTER_CONFIGURATION = new OpaqueToken('ROUTER_CONFIGURATION');
export const ROUTER_FORROOT_GUARD = new OpaqueToken('ROUTER_FORROOT_GUARD');
const pathLocationStrategy = {
provide: LocationStrategy,
useClass: PathLocationStrategy
@ -81,11 +83,17 @@ export const ROUTER_PROVIDERS: any[] = [
*/
@NgModule({declarations: ROUTER_DIRECTIVES, exports: ROUTER_DIRECTIVES})
export class RouterModule {
constructor(@Optional() @Inject(ROUTER_FORROOT_GUARD) guard: any) {}
static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders {
return {
ngModule: RouterModule,
providers: [
ROUTER_PROVIDERS, provideRoutes(routes),
ROUTER_PROVIDERS, provideRoutes(routes), {
provide: ROUTER_FORROOT_GUARD,
useFactory: provideForRootGuard,
deps: [[Router, new Optional(), new SkipSelf()]]
},
{provide: ROUTER_CONFIGURATION, useValue: config ? config : {}}, {
provide: LocationStrategy,
useFactory: provideLocationStrategy,
@ -109,6 +117,14 @@ export function provideLocationStrategy(
new PathLocationStrategy(platformLocationStrategy, baseHref);
}
export function provideForRootGuard(router: Router): any {
if (router) {
throw new BaseException(
`RouterModule.forRoot() called twice. Lazy loaded modules should use RouterModule.forChild() instead.`);
}
return 'guarded';
}
/**
* @stable
*/

View File

@ -1411,7 +1411,34 @@ describe('Integration', () => {
expect(fixture.debugElement.nativeElement)
.toHaveText('lazy-loaded-parent [lazy-loaded-child]');
})));
it('throws an error when forRoot() is used in a lazy context',
fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
@Component({selector: 'lazy', template: 'should not show'})
class LazyLoadedComponent {
}
@NgModule({
declarations: [LazyLoadedComponent],
imports: [RouterModule.forRoot([{path: 'loaded', component: LazyLoadedComponent}])]
})
class LoadedModule {
}
loader.stubbedModules = {expected: LoadedModule};
const fixture = createRoot(router, RootCmp);
router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]);
let recordedError: any = null;
router.navigateByUrl('/lazy/loaded').catch(err => recordedError = err);
advance(fixture);
expect(recordedError.message)
.toEqual(
`RouterModule.forRoot() called twice. Lazy loaded modules should use RouterModule.forChild() instead.`);
})));
it('should combine routes from multiple modules into a single configuration',
fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],

View File

@ -239,6 +239,7 @@ export declare class RouterLinkWithHref implements OnChanges, OnDestroy {
/** @stable */
export declare class RouterModule {
constructor(guard: any);
static forChild(routes: Routes): ModuleWithProviders;
static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders;
}