如何编译运行时生成的 Angular8 代码? [英] How to compile runtime-generated Angular8 code?

查看:28
本文介绍了如何编译运行时生成的 Angular8 代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在运行时创建 Angular 代码,特别是,我使用 SVG 库来创建一个矢量图形,其中包含 Angular 代码指令,如 (click)='myMethod()',反过来,它调用我在 SVG 封闭组件中静态定义的方法.在运行时生成我需要编译创建的模板并将其添加到组件中.我当时在 这篇文章 相当繁琐.我尝试在 Angular 8 应用程序中复制旧代码:

I'm creating Angular code at runtime, in particular, I use a SVG library in order to create a vector graphic that contains Angular code directives like (click)='myMethod()', which, in turn, call methods I've statically defined in the SVG-enclosing component. Being generated at runtime I need to compile the created template and add it to a component. I implemented such code back then with Angular 3 with the help of this post which was quite cumbersome. I tried to the copy the old code in an Angular 8 app:

private addComponent(template: string) {

    @Component({template: template + ' <div #target></div>'})
    class TemplateComponent {

      @ViewChild('target', {static: false, read: ViewContainerRef}) public target;

      constructor() {
      }

      public myMethod() {
        // do something     
      }
    }

    @NgModule({declarations: [TemplateComponent]})
    class TemplateModule {
      @ViewChild('target', {static: false, read: ViewContainerRef}) public target;
    }

    // ERROR in next line:
    const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
    const factory = mod.componentFactories.find((comp) =>
        comp.componentType === TemplateComponent
    );
    this.container.createComponent(factory);
}

现在失败了

ERROR 错误:运行时编译器未加载在 Compiler._throwError (core.js:38932)

ERROR Error: Runtime compiler is not loaded at Compiler._throwError (core.js:38932)

一方面,我不知道为什么会发生该错误.我在互联网上找到的一切都是关于critical函数语法a> 在延迟模块加载中.另一方面,我想知道,如果五个 Angular 主要版本之后,还有其他方法可以做到.我读过 Portals 但它似乎是关于动态加载静态模板,但不是未编译动态生成的模板.期待有人为我指明正确的方向.

On the one hand, I have no clue why that error occurs. Everything I found on the internet was about critical function syntax in lazy module loading. On the other hand, I wonder, if five Angular major versions later, there is an other way to do it. I read about Portals but it seems to be about loading static templates dynamically, but not uncompiled templates generated on the fly. Looking forward to someone pointing me in the right direction.

Post Scriptum: 为可以在 AoT 模式下提供针对 Angular v9 的基本运行代码片段的人添加赏金.它必须包含一个运行时编译的模板(例如来自字符串变量),其中包含关联组件中的方法调用.

Post Scriptum: Adding a Bounty for the one that can provide a basic running code snippet targetting Angular v9 in AoT mode. It has to contain a runtime-compiled template (e.g. from a string variable) containing a method call in the associated component.

推荐答案

JIT 编译器现在默认从 AOT 包中排除,因此您必须手动包含它.您需要安装包 @angular/platform-b​​rowser-dynamic 并将 Compiler 提供程序添加到您的应用程序模块.例如:

The JIT compiler is now excluded by default from AOT bundles so you have to include it manually. You need to install the package @angular/platform-browser-dynamic and add the Compiler providers to your application module. For example:

import { NgModule, COMPILER_OPTIONS, CompilerFactory, Compiler } from '@angular/core';
import { JitCompilerFactory } from '@angular/platform-browser-dynamic';

@NgModule({
  providers: [
    { provide: COMPILER_OPTIONS, useValue: {}, multi: true },
    { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] },
    { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] }
  ]
})
export class AppModule { }

export function createCompiler(compilerFactory: CompilerFactory) {
  return compilerFactory.createCompiler();
}

然后您还必须对代码进行一些小的更改,因为您无法使用 @Component 装饰器将模板设置为变量,它会导致编译错误.装饰器必须在代码中动态运行.

Then you have to also make some small changes to your code because you cannot set the template to be a variable using the @Component decorator it gives a compile error. The decorator must be run dynamically in code.

这是您的方法更新后的更改:

Here is your method updated with the changes:

private addComponent(template: string) {
  class TemplateComponent {

    @ViewChild('target', {static: false, read: ViewContainerRef}) public target;

    constructor() {
    }

    public myMethod() {
      // do something     
    }
  }

  class TemplateModule {
    @ViewChild('target', {static: false, read: ViewContainerRef}) public target;
  }

  const componentType = Component({template: template + '<div #target></div>'})(TemplateComponent)

  const componentModuleType = NgModule({declarations: [componentType]})(TemplateModule)

  const mod = this.compiler.compileModuleAndAllComponentsSync(componentModuleType);
  const factory = mod.componentFactories.find((comp) =>
      comp.componentType === componentType
  );
  this.container.createComponent(factory);
}

我还创建了一个 StackBlitz 示例 在那里你可以看到它的工作.

I have created also a StackBlitz sample where you can see it working.

有关如何执行此操作的更详细示例,请查看此 Angular AOT 动态组件 GitHub 存储库 带有完整样本.

For a more detailed sample on how to do this check this Angular AOT Dynamic Components GitHub repository with a full sample.

我在 关于动态加载组件模板的 Angular GitHub 问题 中发现了这一点.既然您使用它,那么您可以关注该问题以了解最新进展.

I found this in the Angular GitHub issue about dynamically loading component templates. Since you use this it is probably good you follow the issue to be up to date on the developments.

这篇关于如何编译运行时生成的 Angular8 代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆