我有一个问题,即从API响应中“动态”构建模板,但仅限于AoT构建。
我从后端收到了这样的回复:
<h1>Title...</h1>
<some-component></some-componen>
<p>other content</p>
我想像常规的Angular模板那样解析它。
我的组件的简化代码如下所示:
import {
Compiler,
Component,
ComponentFactory,
ComponentRef,
Injector,
Input,
NgModule,
OnChanges,
OnDestroy,
OnInit,
ViewContainerRef
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
export async function createComponentFactory(compiler: Compiler, metadata: Component): Promise> {
const cmpClass = class DynamicComponent {
};
const decoratedCmp = Component(metadata)(cmpClass);
// IMPORT ALL MODULES HERE!!!
@NgModule({imports: [CommonModule, RouterModule], declarations: [decoratedCmp]})
class DynamicHtmlModule {
}
const moduleWithComponentFactory = await compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule);
return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
}
@Component({
selector: 'html-renderer',
templateUrl: './html-renderer.component.html',
styleUrls: ['./html-renderer.component.scss']
})
export class HtmlRendererComponent implements OnInit, OnChanges, OnDestroy {
@Input() content: string;
cmpRef: ComponentRef;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }
ngOnInit(): void {
console.log('init...')
console.log(this.compiler)
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
ngOnChanges() {
const html = this.content;
if (!html) { return; }
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-selector',
template: this.content,
});
createComponentFactory(this.compiler, compMetadata)
.then(factory => {
const injector = Injector.create({providers: [], parent: this.vcRef.injector});
this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
});
}
}
所以,我在content
输入中传递整个数据,然后通过compileModuleAndAllComponentsAsync
方法(https://angular.io/api/core/Compiler#compilemoduleandallcomponentssync)编译所有组件,并且所有组件都在JIT构建中工作。
我想在AoT编译中得到这个工作,因为现在我得到一个错误:Runtime Compiler is not loaded
在示例代码上使用AoT构建时
我也尝试在providers[]
中的app.module.ts中提供编译器,就像这样,它也不起作用:
export function createCompiler(compilerFactory: CompilerFactory) {
return compilerFactory.createCompiler();
}
{provide: COMPILER_OPTIONS, useValue: {}, multi: true},
{provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
{provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]},
我的问题:有没有办法包含带有JIT编译器的延迟加载模块来访问它的方法?
我发现了一些相关的问题,但没有答案:
Error while using @angular compiler in Angular 5 and AOT-Build
EDIT 15.01.2019这是一个在stackblitz.com上运行的JIT示例,带有插值和数据绑定测试:https://stackblitz.com/github/lyczos/angular-dynamic-html-renderer
首先,我为写这个作为答案而道歉,但作为评论,它太长了。
你可以做你想要的事情。事实上,我实际上在今年的ng-conf提出了这个问题。在他关于这个主题的一次会议之后,我采访了Max Koretskyi(又名angularindepth.com的“ng-wizard”作者)。
我必须警告你,虽然他提供的解决方案非常复杂,hacky,你不能依赖它在未来的Angular版本中不会破坏,因为你想要实现的是与Angular框架相悖,而正是Angular团队试图阻止人们这样做。真的,这只是一个噩梦,试图保持,任何新的开发者可能会弹出他们的顶部试图弄清楚我做了什么。哎呀我可能甚至不知道如果我回顾一年+之后我做了什么。
最终,我决定放弃AOT并使用JIT部署我的应用程序,因此我没有后悔自己的决定。如果你确定你真的想进一步追求这个,我建议你去接触Max。从我在ng-conf那里收集到的,他是一个非常友好的人,如果他们有疑问,他会公开邀请人们联系他。希望有所帮助,祝你好运! :)
我去年遇到了同样的问题,并找到了解决办法。我在我的样式指南中使用动态生成的角度组件。这是一个工作示例,适用于AOT编译:
https://github.com/johncrim/angular-dynamic-styleguide
将import 'core-js/es7/reflect';
添加到polyfills.ts
是一个非常明显的关键技巧。
使用ng build --prod
运行动态编译的组件也需要
"buildOptimizer": false,
在angular.json中的生产配置中。请注意,关闭buildOptimizer可能会增加您的捆绑包大小,但至少您将获得预编译大部分代码的好处。