我正在运行时创建Angular代码,特别是,我使用SVG库来创建包含Angular代码指令(如(click)='myMethod()'
)的矢量图形,该代码继而调用了我在static中定义的方法SVG封闭组件。在运行时生成时,我需要编译创建的模板并将其添加到组件中。那时,我在this post的帮助下使用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);
}
现在失败,并带有
错误错误:运行时编译器未加载在Compiler._throwError(core.js:38932)
一方面,我不知道为什么会发生该错误。我在互联网上发现的所有内容都与延迟模块加载中的critical function syntax有关。另一方面,我想知道,如果以后有五个Angular主要版本,还有其他方法可以做到这一点。我读了Portals,但它似乎是关于动态加载静态模板,而不是动态生成的未编译模板。期待有人指出我正确的方向。
Post Scriptum:为可以在AoT模式下以Angular v9为目标的基本运行代码片段的人添加赏金。它必须包含一个运行时编译的模板(例如,来自字符串变量),该模板在相关组件中包含方法调用。
现在默认情况下,AIT捆绑包中不包括JIT编译器,因此您必须手动将其包括在内。您需要安装软件包@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中找到了这个。由于使用了此功能,因此最好跟踪该问题以了解最新动态。