Angular 11 DI 用于动态编译的组件

Angular 11 DI for dynamically compiled components

使用 JitCompilerFactory 并在运行时编译组件是可行的(例如,请参见此处:)但注入动态组件不会:

// (1) define Component metadata
const metadata = new Component({
  selector: "dynamic-selector",
  template: "This is template: {{text}}"    // <---- Interpolation: works
});

// (2) define Component class and decorate
const compClass = class DynamicComponent {
   text: string = 'from';                   // <---- Interpolation: works
   constructor(public s: Service1) { }      // <---- Trying to inject a service: FAILS
};
const decoratedComp = Component(metadata)(compClass);

// (3) define Module class and decorate
const decoratedModule = NgModule({
   imports: [...],
   declarations: [decoratedCmp]
})(class DynamicModule { }) 

// (4 )compile Module and grab the Component Factory
const module  = compiler.compileModuleAndAllComponentsAsync(decoratedModule);
const factory = module.componentFactories.find(x => x.componentType === decoratedCmp);

// (5) render the component using Component Factory
someViewContainerRef.createComponent(factory);

在组件 class 构造函数(上面的#2)中没有 DI 一切都很好,但试图注入原因:

core.js:6210 ERROR Error: Uncaught (in promise): Error: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid.
This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
Please check that 1) the type for the parameter at index 0 is correct and 2) the correct Angular decorators are defined for this class and its ancestors. Error: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid. This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.

我试图根据 Angular 团队对 Angular 9 的回答在 polyfills.ts 中添加 core-js/es/reflectreflect-metadatahttps://github.com/angular/angular/issues/35908 (从 AoT 编译的 Ivy 项目使用 JIT 时出现 DI 错误)。

我应该怎么做才能使 DI 用于 Angular 11 中的动态组件?

回答我的问题以防有人在做同样的事情。感谢那些在 Angular 问题跟踪器上回复的人:https://github.com/angular/angular/issues/41933

DI 失败,因为 TS 编译远远早于我们在运行时创建组件 class 并且 Angular 没有可用于构造函数的元数据信息。所以你可以:

手动提供注入元数据,例如:

(cmpClass as any).ctorParameters = () => [ {type: Service1 }];

或者添加装饰器并在 IIFE 中调用它,例如:

export function Annotate() {
   return klass => klass;
}

const cmpClass = (() => {
   @Annotate()
   class DynamicComponent {
     text: string = "Text";

     constructor(public s: Service1) {
       console.log(s);
     }

     handle() {
       this.text = "Event handler works!";
     }
   }
   return DynamicComponent;
 })();