From 7a8513b64907b3e1aec7c20c8234679c4ebf9135 Mon Sep 17 00:00:00 2001 From: Mihail Goloborodov <Mihail.Goloborodov@nexign-systems.com> Date: Mon, 23 Jan 2023 18:18:41 +0300 Subject: [PATCH 1/2] fix: uiView component injector --- src/directives/uiView.ts | 8 +++----- src/mergeInjector.ts | 39 --------------------------------------- 2 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 src/mergeInjector.ts diff --git a/src/directives/uiView.ts b/src/directives/uiView.ts index cac7a8e04..d33f9fce3 100755 --- a/src/directives/uiView.ts +++ b/src/directives/uiView.ts @@ -33,7 +33,6 @@ import { ViewContext, } from '@uirouter/core'; import { Ng2ViewConfig } from '../statebuilders/views'; -import { MergeInjector } from '../mergeInjector'; /** @hidden */ let id = 0; @@ -291,7 +290,8 @@ export class UIView implements OnInit, OnDestroy { const componentClass = config.viewDecl.component; // Create the component - const compFactoryResolver = componentInjector.get(ComponentFactoryResolver); + const moduleInjector = context.getResolvable(NATIVE_INJECTOR_TOKEN).data; + const compFactoryResolver = moduleInjector.get(ComponentFactoryResolver); const compFactory = compFactoryResolver.resolveComponentFactory(componentClass); this._componentRef = this._componentTarget.createComponent(compFactory, undefined, componentInjector); @@ -322,10 +322,8 @@ export class UIView implements OnInit, OnDestroy { newProviders.push({ provide: UIView.PARENT_INJECT, useValue: parentInject }); const parentComponentInjector = this.viewContainerRef.injector; - const moduleInjector = context.getResolvable(NATIVE_INJECTOR_TOKEN).data; - const mergedParentInjector = new MergeInjector(moduleInjector, parentComponentInjector); - return ReflectiveInjector.resolveAndCreate(newProviders, mergedParentInjector); + return Injector.create({ providers: newProviders, parent: parentComponentInjector }); } /** diff --git a/src/mergeInjector.ts b/src/mergeInjector.ts deleted file mode 100644 index b82a45a9d..000000000 --- a/src/mergeInjector.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Injector } from '@angular/core'; - -/** - * Merge two injectors - * - * This class implements the Injector ng2 interface but delegates - * to the Injectors provided in the constructor. - */ -export class MergeInjector implements Injector { - static NOT_FOUND = {}; - private injectors: Injector[]; - constructor(...injectors: Injector[]) { - if (injectors.length < 2) throw new Error('pass at least two injectors'); - this.injectors = injectors; - } - - /** - * Get the token from the first injector which contains it. - * - * Delegates to the first Injector.get(). - * If not found, then delegates to the second Injector (and so forth). - * If no Injector contains the token, return the `notFoundValue`, or throw. - * - * @param token the DI token - * @param notFoundValue the value to return if none of the Injectors contains the token. - * @returns {any} the DI value - */ - get(token: any, notFoundValue?: any): any { - for (let i = 0; i < this.injectors.length; i++) { - const val = this.injectors[i].get(token, MergeInjector.NOT_FOUND); - if (val !== MergeInjector.NOT_FOUND) return val; - } - - if (arguments.length >= 2) return notFoundValue; - - // This will throw the DI Injector error - this.injectors[0].get(token); - } -} From 930accf320db1fa48659b13ed2c18859650ab9f7 Mon Sep 17 00:00:00 2001 From: Mihail Goloborodov <Mihail.Goloborodov@nexign-systems.com> Date: Fri, 10 Mar 2023 16:35:44 +0300 Subject: [PATCH 2/2] fix: remove deprecated NgModuleFactory, Compiler, ComponentFactoryResolver --- src/directives/uiView.ts | 24 ++++++++++++-------- src/lazyLoad/lazyLoadNgModule.ts | 39 +++++--------------------------- 2 files changed, 21 insertions(+), 42 deletions(-) diff --git a/src/directives/uiView.ts b/src/directives/uiView.ts index d33f9fce3..a9a54ebb3 100755 --- a/src/directives/uiView.ts +++ b/src/directives/uiView.ts @@ -1,14 +1,13 @@ import { Component, - ComponentFactory, - ComponentFactoryResolver, + ComponentMirror, ComponentRef, Inject, Injector, Input, OnDestroy, OnInit, - ReflectiveInjector, + reflectComponentType, ViewChild, ViewContainerRef, } from '@angular/core'; @@ -57,7 +56,7 @@ interface InputMapping { * * @internal */ -const ng2ComponentInputs = (factory: ComponentFactory<any>): InputMapping[] => { +const ng2ComponentInputs = (factory: ComponentMirror<any>): InputMapping[] => { return factory.inputs.map((input) => ({ prop: input.propName, token: input.templateName })); }; @@ -291,12 +290,19 @@ export class UIView implements OnInit, OnDestroy { // Create the component const moduleInjector = context.getResolvable(NATIVE_INJECTOR_TOKEN).data; - const compFactoryResolver = moduleInjector.get(ComponentFactoryResolver); - const compFactory = compFactoryResolver.resolveComponentFactory(componentClass); - this._componentRef = this._componentTarget.createComponent(compFactory, undefined, componentInjector); + + this._componentRef = this._componentTarget.createComponent(componentClass, { + injector: componentInjector, + environmentInjector: moduleInjector + }); // Wire resolves to @Input()s - this._applyInputBindings(compFactory, this._componentRef.instance, context, componentClass); + this._applyInputBindings( + reflectComponentType(componentClass), + this._componentRef.instance, + context, + componentClass + ); } /** @@ -332,7 +338,7 @@ export class UIView implements OnInit, OnDestroy { * Finds component inputs which match resolves (by name) and sets the input value * to the resolve data. */ - private _applyInputBindings(factory: ComponentFactory<any>, component: any, context: ResolveContext, componentClass) { + private _applyInputBindings(factory: ComponentMirror<any>, component: any, context: ResolveContext, componentClass) { const bindings = this._uiViewData.config.viewDecl['bindings'] || {}; const explicitBoundProps = Object.keys(bindings); diff --git a/src/lazyLoad/lazyLoadNgModule.ts b/src/lazyLoad/lazyLoadNgModule.ts index e4d362ac1..b25f7580d 100644 --- a/src/lazyLoad/lazyLoadNgModule.ts +++ b/src/lazyLoad/lazyLoadNgModule.ts @@ -1,11 +1,10 @@ -import { NgModuleRef, Injector, NgModuleFactory, Type, Compiler } from '@angular/core'; +import { NgModuleRef, Injector, Type, createNgModule } from '@angular/core'; import { Transition, LazyLoadResult, UIRouter, Resolvable, NATIVE_INJECTOR_TOKEN, - isString, unnestR, inArray, StateObject, @@ -72,42 +71,16 @@ export function loadNgModule( ): (transition: Transition, stateObject: StateDeclaration) => Promise<LazyLoadResult> { return (transition: Transition, stateObject: StateDeclaration) => { const ng2Injector = transition.injector().get(NATIVE_INJECTOR_TOKEN); - - const createModule = (factory: NgModuleFactory<any>) => factory.create(ng2Injector); - + const unwrapEsModuleDefault = x => (x && x.__esModule && x['default'] ? x['default'] : x); const applyModule = (moduleRef: NgModuleRef<any>) => applyNgModule(transition, moduleRef, ng2Injector, stateObject); - return loadModuleFactory(moduleToLoad, ng2Injector).then(createModule).then(applyModule); + return Promise.resolve(moduleToLoad()) + .then(unwrapEsModuleDefault) + .then((ngModule: Type<any>) => createNgModule(ngModule, ng2Injector)) + .then(applyModule); }; } -/** - * Returns the module factory that can be used to instantiate a module - * - * For a Type<any> or Promise<Type<any>> this: - * - Compiles the component type (if not running with AOT) - * - Returns the NgModuleFactory resulting from compilation (or direct loading if using AOT) as a Promise - * - * @internal - */ -export function loadModuleFactory( - moduleToLoad: ModuleTypeCallback, - ng2Injector: Injector -): Promise<NgModuleFactory<any>> { - const compiler: Compiler = ng2Injector.get(Compiler); - - const unwrapEsModuleDefault = (x) => (x && x.__esModule && x['default'] ? x['default'] : x); - - return Promise.resolve(moduleToLoad()) - .then(unwrapEsModuleDefault) - .then((t: NgModuleFactory<any> | Type<any>) => { - if (t instanceof NgModuleFactory) { - return t; - } - return compiler.compileModuleAsync(t); - }); -} - /** * Apply the UI-Router Modules found in the lazy loaded module. *