Skip to content

Commit

Permalink
fix(upgrade): component injectors should not link the module injector…
Browse files Browse the repository at this point in the history
… tree (angular#15385)
  • Loading branch information
vicb authored and juleskremer committed Aug 24, 2017
1 parent a1499ae commit 5d71cff
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/core/src/core_private_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
export {isObservable as ɵisObservable, isPromise as ɵisPromise, merge as ɵmerge} from './util/lang';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';
2 changes: 1 addition & 1 deletion packages/core/src/view/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ function callFactory(
// - el2.injector.get(token, default)
// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
// - mod2.injector.get(token, default)
const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
export const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};

export function resolveDep(
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
Expand Down
29 changes: 24 additions & 5 deletions packages/upgrade/src/static/upgrade_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Injector, NgModule, NgZone, Testability} from '@angular/core';
import {Injector, NgModule, NgZone, Testability, ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '@angular/core';

import * as angular from '../common/angular1';
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $PROVIDE, $ROOT_SCOPE, INJECTOR_KEY, UPGRADE_MODULE_NAME} from '../common/constants';
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $PROVIDE, INJECTOR_KEY, UPGRADE_MODULE_NAME} from '../common/constants';
import {controllerKey} from '../common/util';

import {angular1Providers, setTempInjectorRef} from './angular1_providers';



/**
* @whatItDoes
*
Expand Down Expand Up @@ -135,12 +134,16 @@ export class UpgradeModule {
* The AngularJS `$injector` for the upgrade application.
*/
public $injector: any /*angular.IInjectorService*/;
/** The Angular Injector **/
public injector: Injector;

constructor(
/** The root {@link Injector} for the upgrade application. */
public injector: Injector,
injector: Injector,
/** The bootstrap zone for the upgrade application */
public ngZone: NgZone) {}
public ngZone: NgZone) {
this.injector = new NgAdapterInjector(injector);
}

/**
* Bootstrap an AngularJS application from this NgModule
Expand Down Expand Up @@ -234,3 +237,19 @@ export class UpgradeModule {
}
}
}

class NgAdapterInjector implements Injector {
constructor(private modInjector: Injector) {}

// When Angular locate a service in the component injector tree, the not found value is set to
// `NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR`. In such a case we should not walk up to the module
// injector.
// AngularJS only supports a single tree and should always check the module injector.
get(token: any, notFoundValue?: any): any {
if (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
return notFoundValue;
}

return this.modInjector.get(token, notFoundValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Component, EventEmitter, NgModule, OnChanges, OnDestroy, SimpleChanges, destroyPlatform} from '@angular/core';
import {Compiler, Component, ComponentFactoryResolver, EventEmitter, Injector, NgModule, NgModuleRef, OnChanges, OnDestroy, SimpleChanges, destroyPlatform} from '@angular/core';
import {async} from '@angular/core/testing';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
Expand Down Expand Up @@ -361,5 +361,55 @@ export function main() {
expect(multiTrim(document.body.textContent)).toBe('parent(child)');
});
}));

it('should work with ng2 lazy loaded components', async(() => {

let componentInjector: Injector;

@Component({selector: 'ng2', template: ''})
class Ng2Component {
constructor(injector: Injector) { componentInjector = injector; }
}

@NgModule({
declarations: [Ng2Component],
entryComponents: [Ng2Component],
imports: [BrowserModule, UpgradeModule],
})
class Ng2Module {
ngDoBootstrap() {}
}

@Component({template: ''})
class LazyLoadedComponent {
constructor(public module: NgModuleRef<any>){};
}

@NgModule({
declarations: [LazyLoadedComponent],
entryComponents: [LazyLoadedComponent],
})
class LazyLoadedModule {
}

const ng1Module = angular.module('ng1', []).directive(
'ng2', downgradeComponent({component: Ng2Component}));

const element = html('<ng2></ng2>');

bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => {
const modInjector = upgrade.injector;
// Emulate the router lazy loading a module and creating a component
const compiler = modInjector.get(Compiler);
const modFactory = compiler.compileModuleSync(LazyLoadedModule);
const childMod = modFactory.create(modInjector);
const cmpFactory =
childMod.componentFactoryResolver.resolveComponentFactory(LazyLoadedComponent);
const lazyCmp = cmpFactory.create(componentInjector);

expect(lazyCmp.instance.module).toBe(childMod.injector);
});

}));
});
}

0 comments on commit 5d71cff

Please sign in to comment.