这是一个使用eval 的动态模板和动态组件类代码的扩展解决方案。请参阅下面的不带 eval 的变体。
Stackblitz Example 不使用 eval。
import { Component, ViewChild, ViewContainerRef, NgModule, Compiler, Injector, NgModuleRef } from '@angular/core';
import {CommonModule} from "@angular/common";
import { RouterModule } from "@angular/router"
@Component({
selector: 'app-root',
template: `<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
</div>
<div #content></div>`
})
export class AppComponent {
title = 'Angular';
@ViewChild("content", { read: ViewContainerRef })
content: ViewContainerRef;
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>, ) {
}
// Here we create the component.
private createComponentFromRaw(klass: string, template: string, styles = null) {
// Let's say your template looks like `<h2><some-component [data]="data"></some-component>`
// As you see, it has an (existing) angular component `some-component` and it injects it [data]
// Now we create a new component. It has that template, and we can even give it data.
var c = null;
eval(`c = ${klass}`);
let tmpCmp = Component({ template, styles })(c);
// Now, also create a dynamic module.
const tmpModule = NgModule({
imports: [CommonModule, RouterModule],
declarations: [tmpCmp],
// providers: [] - e.g. if your dynamic component needs any service, provide it here.
})(class { });
// Now compile this module and component, and inject it into that #vc in your current component template.
this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
.then((factories) => {
const f = factories.componentFactories[factories.componentFactories.length - 1];
var cmpRef = f.create(this.injector, [], undefined, this.moduleRef);
cmpRef.instance.name = 'app-dynamic';
this.content.insert(cmpRef.hostView);
});
}
ngAfterViewInit() {
this.createComponentFromRaw(`class _ {
constructor(){
this.data = {some: 'data'};
}
ngOnInit() { }
ngAfterViewInit(){}
clickMe(){ alert("Hello eval");}
}`, `<button (click)="clickMe()">Click Me</button>`)
}
}
这是一个没有动态类代码的小变化。通过类绑定动态模板变量没有成功,而是使用了一个函数:
function A() {
this.data = { some: 'data' };
this.clickMe = () => { alert("Hello tmpCmp2"); }
}
let tmpCmp2 = Component({ template, styles })(new A().constructor);