Home > other >  Generating unattached dynamic components in Angular
Generating unattached dynamic components in Angular

Time:11-23

I went through this issue while working on the ScheduleJS framework. At some point I am provided with a HTMLCanvasElement which I want to replace with a dynamically generated component programatically. To do so, and to keep the code as clean as possible, I'd like to create my own Angular components at runtime and use the HTMLCanvasElement.replaceWith(component) method from the provided HTMLCanvasElement replacing the canvas with the dynamically created component.

Here is the Angular service I came up with, which does the job the way I expected:

import {ApplicationRef, ComponentFactoryResolver, ComponentRef, Injectable, Injector, Type} from "@angular/core";

import {ReplacementComponent} from "xxx"; // This is a higher order type of Component

@Injectable({providedIn: "root"})
export class DynamicComponentGenerator {

  // Attributes

  private _components: Map<string, ComponentRef<ReplacementComponent>> = new Map();
  private _currentKey: number = 0;

  // Constructor

  constructor(private _appRef: ApplicationRef,
              private _resolver: ComponentFactoryResolver,
              private _injector: Injector) { }

  // Methods

  create(componentType: Type<ReplacementComponent>): ComponentRef<ReplacementComponent> {
    const componentRef = componentType instanceof ComponentRef
      ? componentType
      : this._resolver.resolveComponentFactory(componentType).create(this._injector);
    this._appRef.attachView(componentRef.hostView);
    this._components.set(`${this._currentKey}`, componentRef);
    componentRef.instance.key = `${this._currentKey}`;
    this._currentKey  = 1;
    return componentRef;
  }

  remove(componentKey: string): void {
    const componentRef = this._components.get(componentKey);
    if (componentRef) {
      this._appRef.detachView(componentRef.hostView);
      componentRef.destroy();
      this._components.delete(componentKey);
    }
  }

  clear(): void {
    this._components.forEach((componentRef, key) => {
      this._appRef.detachView(componentRef.hostView);
      componentRef.destroy();
      this._components.delete(key);
    });
    this._currentKey = 0;
  }

}

So basically this service lets me create a component with .create(ComponentClass) remove it by providing the component key .remove(key) and clear() to remove all the components.

My issues are the following:

  • The ComponentFactoryResolver class is deprecated, should I use it anyways?
  • Could not manage to use the newer API to create unattached components (not able to have access to an Angular hostView)
  • Is there a better way to do this?

Thank you for reading me.

CodePudding user response:

You could try using new createComponent function:

import { createComponent, ... } from "@angular/core";

const componentRef = 
    createComponent(componentType, { environmentInjector: this._appRef.injector});
this._appRef.attachView(componentRef.hostView);
  • Related