typescript - Cómo crear un componente de clase Angular y una plantilla HTML dinámicamente, mediante cadena
Me gustaría saber si es posible para mí cargar un componente de clase (TypeScript) y una plantilla (HTML) mediante una cadena y ensamblar dinámicamente mi componente. Logré crear algo, pero estoy cometiendo un error cuando intento referenciar o importar algo en mi componente de clase dinámico de Angular.
Ejemplo Mi Código StackBlitz
o
dynamic-template.component.ts
import {Compiler, Component, ComponentRef, Injector, NgModule, NgModuleRef, ViewChild, ViewContainerRef} from "@angular/core";
import {CommonModule} from "@angular/common";
import {RouterModule} from "@angular/router";
@Component({
selector: 'dynamic-template',
template: `<div #content></div>`
})
export class DynamicTemplateComponent {
@ViewChild("content", { read: ViewContainerRef }) content: ViewContainerRef;
private cmpRef: ComponentRef<any>;
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>){}
ngAfterViewInit() {
// Here, get your HTML and Class from backend.
let klass = `
import { HttpClient } from '@angular/common/http';
class DynamicComponent {
constructor(public http: HttpClient){
this.http.get<any>('https://jsonplaceholder.typicode.com/posts').subscribe(result => {
console.log(result);
}, error => console.error(error));
this.data = {some: 'Click Me'};
}
ngOnInit() {
}
ngAfterViewInit(){
}
clickMe(){
alert("Hello eval");
}
}`;
let template = `<button (click)="clickMe()">{{data.some}}</button>`;
this.createComponentFromRaw(klass, template);
}
// Here we create the component.
// 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);
});
}
}

