如何编译运行时生成的 Angular8 代码?
How to compile runtime-generated Angular8 code?
我正在运行时创建 Angular 代码,特别是,我使用 SVG 库来创建包含 Angular 代码指令的矢量图形,例如 (click)='myMethod()'
, ,依次调用我在 SVG 封闭组件中静态定义的方法。在运行时生成我需要编译创建的模板并将其添加到组件中。我当时用 Angular 3 在 的帮助下实现了这样的代码,这非常麻烦。我尝试在 Angular 8 应用程序中复制旧代码:
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 Error: Runtime compiler is not loaded
at Compiler._throwError (core.js:38932)
一方面,我不知道为什么会出现该错误。我在互联网上找到的所有内容都是关于 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 但它似乎是关于动态加载静态模板,而不是动态生成的未编译模板。期待有人给我指明正确的方向。
Post Scriptum: 为可以在 AoT 模式下提供基本 运行 代码片段目标 Angular v9 的赏金.它必须包含一个运行时编译的模板(例如来自字符串变量),该模板包含关联组件中的方法调用。
JIT 编译器现在默认从 AOT 包中排除,因此您必须手动包含它。您需要安装包 @angular/platform-browser-dynamic
并将 Compiler
提供程序添加到您的应用程序模块。例如:
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
装饰器将模板设置为变量,这会导致编译错误。装饰器必须在代码中动态 运行。
这是您的方法更新后的变化:
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 sample,您可以在其中查看它的运行情况。
有关如何执行此操作的更详细示例,请检查此 Angular AOT Dynamic Components GitHub repository 和完整示例。
我在 Angular GitHub issue about dynamically loading component templates 中找到了这个。既然你使用了这个,那么你关注这个问题以了解最新的进展可能是件好事。
我正在运行时创建 Angular 代码,特别是,我使用 SVG 库来创建包含 Angular 代码指令的矢量图形,例如 (click)='myMethod()'
, ,依次调用我在 SVG 封闭组件中静态定义的方法。在运行时生成我需要编译创建的模板并将其添加到组件中。我当时用 Angular 3 在
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 Error: Runtime compiler is not loaded at Compiler._throwError (core.js:38932)
一方面,我不知道为什么会出现该错误。我在互联网上找到的所有内容都是关于 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 但它似乎是关于动态加载静态模板,而不是动态生成的未编译模板。期待有人给我指明正确的方向。
Post Scriptum: 为可以在 AoT 模式下提供基本 运行 代码片段目标 Angular v9 的赏金.它必须包含一个运行时编译的模板(例如来自字符串变量),该模板包含关联组件中的方法调用。
JIT 编译器现在默认从 AOT 包中排除,因此您必须手动包含它。您需要安装包 @angular/platform-browser-dynamic
并将 Compiler
提供程序添加到您的应用程序模块。例如:
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
装饰器将模板设置为变量,这会导致编译错误。装饰器必须在代码中动态 运行。
这是您的方法更新后的变化:
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 sample,您可以在其中查看它的运行情况。
有关如何执行此操作的更详细示例,请检查此 Angular AOT Dynamic Components GitHub repository 和完整示例。
我在 Angular GitHub issue about dynamically loading component templates 中找到了这个。既然你使用了这个,那么你关注这个问题以了解最新的进展可能是件好事。