Skip to content

Commit

Permalink
fix(router): instantiate lazy loaded module only once
Browse files Browse the repository at this point in the history
  • Loading branch information
DzmitryShylovich committed Jan 31, 2017
1 parent 14e9751 commit efad23d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
13 changes: 12 additions & 1 deletion modules/@angular/router/src/router_config_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ import {mergeMap} from 'rxjs/operator/mergeMap';
import {LoadChildren, Route} from './config';
import {flatten, wrapIntoObservable} from './utils/collection';

const UNDEFINED: any = {};

export class MergeInjector implements Injector {
constructor(private componentInjector: Injector, private moduleInjector: Injector) {}

get(token: any, notFoundValue?: any): any {
const value = this.componentInjector.get(token, UNDEFINED);
return value !== UNDEFINED ? value : this.moduleInjector.get(token, notFoundValue);
}
}

/**
* @experimental
*/
Expand All @@ -33,7 +44,7 @@ export class RouterConfigLoader {
load(parentInjector: Injector, loadChildren: LoadChildren): Observable<LoadedRouterConfig> {
return map.call(this.loadModuleFactory(loadChildren), (r: NgModuleFactory<any>) => {
const ref = r.create(parentInjector);
const injectorFactory = (parent: Injector) => r.create(parent).injector;
const injectorFactory = (parent: Injector) => new MergeInjector(parent, ref.injector);
return new LoadedRouterConfig(
flatten(ref.injector.get(ROUTES)), ref.injector, ref.componentFactoryResolver,
injectorFactory);
Expand Down
42 changes: 42 additions & 0 deletions modules/@angular/router/test/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2258,6 +2258,48 @@ describe('Integration', () => {
})));
});

it('should instantiate lazy loaded module only once',
fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader],
(router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => {
let instantiatedTimes: number = 0;
@Component({
selector: 'lazy',
template: 'lazy-loaded-parent [<router-outlet></router-outlet>]'
})
class ParentLazyLoadedComponent {
}

@Component({selector: 'lazy', template: 'lazy-loaded-child'})
class ChildLazyLoadedComponent {
}

@NgModule({
declarations: [ParentLazyLoadedComponent, ChildLazyLoadedComponent],
imports: [RouterModule.forChild([{
path: 'loaded',
component: ParentLazyLoadedComponent,
children: [{path: 'child', component: ChildLazyLoadedComponent}]
}])]
})
class LoadedModule {
constructor() { instantiatedTimes++; }
}

loader.stubbedModules = {expected: LoadedModule};

const fixture = createRoot(router, RootCmp);

router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]);

router.navigateByUrl('/lazy/loaded/child');
advance(fixture);

expect(location.path()).toEqual('/lazy/loaded/child');
expect(fixture.nativeElement).toHaveText('lazy-loaded-parent [lazy-loaded-child]');
expect(instantiatedTimes).toEqual(1);
})));

it('works when given a callback',
fakeAsync(inject(
[Router, Location, NgModuleFactoryLoader], (router: Router, location: Location) => {
Expand Down

0 comments on commit efad23d

Please sign in to comment.