Búsqueda de sitios web

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);
      });

  }
}