2

Trying to generate components on-the-fly (based on this repo) I am facing an issue: I can generate the html template by reading stored templates using the template const below and assigning it the htmlTemplate for a component (here I named it application), but I can't think of a way to use a stored TypeScript code for the same component named say tsTemplate. How should I do it?

See code:

import { Component, OnInit, OnDestroy, ComponentRef, ViewChild, ViewContainerRef, Compiler, Injector, NgModuleRef, NgModule } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

import { Application } from '../application.model';
import { ApplicationService } from '../application.service';

@Component({
  selector: 'app-app-frame',
  templateUrl: './app-frame.component.html',
  styleUrls: ['./app-frame.component.css']
})
export class AppFrameComponent implements OnInit, OnDestroy {
  @ViewChild('vc', { read: ViewContainerRef }) _container: ViewContainerRef;

  application: Application;
  appIndex: number;
  cmpRef: ComponentRef<any>;

  constructor(private route: ActivatedRoute, 
              private applicationService: ApplicationService,
              private _compiler: Compiler, private _injector: Injector, private _m: NgModuleRef<any>
              ) { }

  ngOnInit() {
    this.appIndex = +this.route.snapshot.params['id'];
    this.application = this.applicationService.getApp(this.appIndex);

    this.route.params.subscribe(
        (params: Params)=>{
            this.appIndex = params['id'];
            this.application = this.applicationService.getApp(params['id']);

            if(this.cmpRef) {
              this.cmpRef.destroy();
            }
            ///// HERE ////////
            const template = this.application.htmlTemplate;
            const tmpCmp = Component({template: template})(class {});
            const tmpModule = NgModule({declarations: [tmpCmp]})(class {});

            this._compiler.compileModuleAndAllComponentsAsync(tmpModule)
            .then((factories) => {
              const f = factories.componentFactories[0];
              this.cmpRef = f.create(this._injector, [], null, this._m);
          this.cmpRef.instance.name = this.application.name;
          this._container.insert(this.cmpRef.hostView);
            })
        });
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
  }

}
Rudy Del
  • 21
  • 4
  • so what is your problem? is the code you showed working? – Max Koretskyi Jan 03 '18 at 15:32
  • The code works, but I would like to find a way to provide dynamic typescript class (say an `application.tsTemplate`) associated to the dynamic `htmlTemplate`. The idea is to query a db, get the components (html **and** logic) and inject them. The missing piece is the Typescript. – Rudy Del Jan 03 '18 at 15:45
  • I don't understand what `dynamic typescript class` means, in the code above `class {}` is a typescript/javascript class defined on the fly – Max Koretskyi Jan 03 '18 at 15:47
  • Exactly, so let's say I want to generate 2 components otf, using a parent component + ngFor looping over "let application of applications". Each component has its html and js/ts stored respectively in two field of a db row (so 2 rows, for 2 components). I am able, with the code above, to retrieve the html for each component, but I am looking for a solution to do the same for the js/ts (the `class {}` you are mentioning). How can I put the class in a variable in order to store it then use it with something like `const tmpCmp = Component({template: template})(**this.application.tsTemplate**);` ? – Rudy Del Jan 03 '18 at 16:43
  • like this `const dynamicclass = class {}; Component({template: template})(dynamicclass);`? – Max Koretskyi Jan 03 '18 at 16:46
  • Yes! This returned an error at runtime: _this Type class_2 is part of the declarations of 2 modules...etc_ . So I went all the way and stored also the modules and their declarations so they don't have the same generated names and Bingo! Sorry for my bad explanations and thanks a lot for yours! – Rudy Del Jan 03 '18 at 17:37
  • you're welcome) good luck – Max Koretskyi Jan 03 '18 at 17:38
  • If you want to add an answer, I will be able to mark this as resolved! – Rudy Del Jan 03 '18 at 17:39
  • not sure what the answer should be, so will probably won't do this – Max Koretskyi Jan 03 '18 at 17:46
  • @RudyDel Were you able to crack this one? – Keerthivasan Aug 06 '18 at 07:43
  • @RudyDel Can you add some code. I am not able to run *ngFor or *ngIf in template which loads dynamically. – abhy Dec 19 '18 at 11:15
  • @Keerthivasan: I switched tech (Vue.js, but same stuff anyway) but I am confident this is doable – Rudy Del Dec 20 '18 at 13:23
  • @abhy I am sorry, I am not working on this anymore – Rudy Del Dec 20 '18 at 13:25

0 Answers0