fix(upgrade): component injectors should not link the module injector tree (#15385)
This commit is contained in:
parent
a50d79df47
commit
ea49a95bd9
|
@ -26,3 +26,4 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
|
||||||
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
|
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
|
||||||
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
|
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
|
||||||
export {isObservable as ɵisObservable, isPromise as ɵisPromise, merge as ɵmerge} from './util/lang';
|
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';
|
||||||
|
|
|
@ -341,7 +341,7 @@ function callFactory(
|
||||||
// - el2.injector.get(token, default)
|
// - el2.injector.get(token, default)
|
||||||
// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
|
// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
|
||||||
// - mod2.injector.get(token, default)
|
// - mod2.injector.get(token, default)
|
||||||
const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
|
export const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
|
||||||
|
|
||||||
export function resolveDep(
|
export function resolveDep(
|
||||||
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
|
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
|
||||||
|
|
|
@ -6,16 +6,15 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 * 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 {controllerKey} from '../common/util';
|
||||||
|
|
||||||
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes
|
* @whatItDoes
|
||||||
*
|
*
|
||||||
|
@ -135,12 +134,16 @@ export class UpgradeModule {
|
||||||
* The AngularJS `$injector` for the upgrade application.
|
* The AngularJS `$injector` for the upgrade application.
|
||||||
*/
|
*/
|
||||||
public $injector: any /*angular.IInjectorService*/;
|
public $injector: any /*angular.IInjectorService*/;
|
||||||
|
/** The Angular Injector **/
|
||||||
|
public injector: Injector;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
/** The root {@link Injector} for the upgrade application. */
|
/** The root {@link Injector} for the upgrade application. */
|
||||||
public injector: Injector,
|
injector: Injector,
|
||||||
/** The bootstrap zone for the upgrade application */
|
/** 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
|
* Bootstrap an AngularJS application from this NgModule
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* 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 {async} from '@angular/core/testing';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
|
@ -361,5 +361,55 @@ export function main() {
|
||||||
expect(multiTrim(document.body.textContent)).toBe('parent(child)');
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue