Search code examples
angularangular15

How to dynamically create Angular(15) component?


I have a function which would create an In memory angular component, add it as a declaration for an In memory Angular Module and then compile the same

something like this:

createComponent(template, selector) {
     @Component({
      selector: selector,
      template: template
    })
    class AngularComponent implements OnInit, AfterViewInit
    {
      @Output() onAfterViewInit = new EventEmitter<boolean>();

      ngOnInit(): void {
       // some event
      }

      ngAfterViewInit(): void {
        // some event
      }
    }

    @NgModule({
      declarations: [AngularComponent],
      imports: [],
      exports: [],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    })
    class TemplateModule {
    }
    const compiled = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
}

This used to work for Angular 10. But, since Ivy compiler is introduced now, it would not work for Angular 15. Could anyone please suggest updates for the above function to make it compatible for Angular 15?

Edit

I tried the following:

    class AngularComponent {
    }
    const componentType = Component({ template: html, selector: selectedComponent})(AngularComponent);

This works until I add implements OnInit, AfterViewInit for AngularComponent

Once I add the same, I get following error:

error NG2007: Class is using Angular features but is not decorated. Please add an explicit Angular decorator.

EDIT 2

Based on @Anton's comment, I made following changes:

createComponent(template, selector) {
    @Directive()
    class AngularComponent implements OnInit, AfterViewInit{
      @Output() onAfterViewInit = new EventEmitter<boolean>();

      ngOnInit(): void {
        // method call
      }

      ngAfterViewInit(): void {
        this.onAfterViewInit.emit();
      }
    }

    const angularComponentType = Component({
      template: html,
      selector: selectedComponent
    })(AngularComponent);
}

Now the ng build works, but on ng serve I am getting error on browser console:

Error: NG0202: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid.
This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.

Please check that 1) the type for the parameter at index 0 is correct and 2) the correct Angular decorators are defined for this class and its ancestors.

Solution

  • After making changes and proper testing here is what worked for me:

    Created a component as base class

    import { Component, EventEmitter, OnInit, Output } from "@angular/core";
    
    @Component({
        template: ''
    })
    export class AngularComponent implements OnInit {
        @Output() onAfterViewInit = new EventEmitter<boolean>();
    
        ngOnInit(): void {
            this.onAfterViewInit.emit();
        }
    }
    

    And then created a dynamic component extending the base class:

    import { Component } from '@angular/core';
    createComponent(html, selector) {
        const angularComponentType = Component({
            template: html,
            selector: selector
        })(class extends AngularComponent {
              ngOnInit(): void {
                localfunction(this);
              }
          });
    }