【问题标题】:Angular 11 DI for dynamically compiled componentsAngular 11 DI 用于动态编译的组件
【发布时间】:2021-07-25 07:50:13
【问题描述】:

使用 JitCompilerFactory 并在运行时编译组件有效(例如,请参见此处:https://stackoverflow.com/a/67122569/15816951)但注入动态组件不起作用:

// (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);

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

core.js:6210 ERROR 错误:未捕获(在承诺中):错误:此构造函数与 Angular 依赖注入不兼容,因为它在参数列表索引 0 处的依赖无效。
如果依赖类型是像字符串这样的原始类型,或者此类的祖先缺少 Angular 装饰器,则可能会发生这种情况。
请检查 1) 索引 0 处的参数类型是否正确,以及 2) 为此类及其祖先定义了正确的 Angular 装饰器。 错误:此构造函数与 Angular 依赖注入不兼容,因为它在参数列表索引 0 处的依赖无效。 如果依赖类型是像字符串这样的原始类型,或者此类的祖先缺少 Angular 装饰器,则可能会发生这种情况。

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

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

【问题讨论】:

    标签: angular dependency-injection angular-ivy dynamic-compilation


    【解决方案1】:

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

    DI 失败是因为 TS 编译早于我们在运行时创建组件类的时间点,并且 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;
     })();
    

    【讨论】:

      猜你喜欢
      • 2021-07-10
      • 2016-07-02
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 2018-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多