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

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

问题描述

我在运行时创建Angular代码,特别是,我使用SVG库来创建包含Angular代码指令(如(click)='myMethod()')的矢量图形,依次调用我在其中静态定义的方法SVG封闭组件.在运行时生成时,我需要编译创建的模板并将其添加到组件中.那时,我借助

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);
}

现在以

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

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

一方面,我不知道为什么会发生该错误.我在互联网上发现的所有内容都与 关键函数语法在延迟模块加载中.另一方面,我想知道,如果以后有五个Angular主要版本,还有其他方法可以做到这一点.我阅读了有关门户网站的信息,但这似乎是关于动态加载静态模板,但并非未编译即时生成的模板.期待有人指出我正确的方向.

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.

后脚本::为可以在AoT模式下以Angular v9为目标的基本运行代码段的Bounty添加赏金.它必须包含运行时编译的模板(例如,来自字符串变量),该模板在相关组件中包含方法调用.

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.

推荐答案

现在默认情况下,AIT捆绑包中不包含JIT编译器,因此您必须手动将其包括在内.您需要安装软件包@angular/platform-browser-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.

我在有关动态加载组件模板的GitHub Angular问题中找到了这一点.由于使用了此功能,因此最好跟踪该问题以了解最新动态.

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天全站免登陆