Angular

createComponent API in Angular

Angular v14.1 added a new function named createComponent. This function can cover the use-cases where the ComponentFactory symbol was previously used. The function allows creating...

Written by Luci · 1 min read >

Angular v14.1 added a new function named createComponent. This function can cover the use-cases where the ComponentFactory symbol was previously used.

The function allows creating a ComponentRef instance based on provided Component and a set of options:

import { ApplicationRef, createComponent, EnvironmentInjector } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class ToastService {

  constructor(
    private appRef: ApplicationRef,
    private injector: EnvironmentInjector
  ) { }

  open(text: string) {
    // Create a `ComponentRef` instance.
    const dialogRef = createComponent(ToastComponent, {
      environmentInjector: this.injector
    });

    dialogRef.setInput('text', text);

    document.body.appendChild(dialogRef.location.nativeElement);

    // Register the newly created ref using the `ApplicationRef` instance
    // to include the component view into change detection cycles.
    this.appRef.attachView(dialogRef.hostView);
  }
}

It’s possible to pass a new environment injector inherited from the current one:

export class ToastService {

  constructor(
    private appRef: ApplicationRef,
    private injector: EnvironmentInjector
  ) { }

  open(text: string) {
    const newEnvInjector = createEnvironmentInjector([
      {
        provide: 'MyToken',
        useValue: 'Token'
      }
    ], this.injector);

    const dialogRef = createComponent(ToastComponent, {
      environmentInjector: newEnvInjector
    });

    dialogRef.setInput('text', text);

    document.body.appendChild(dialogRef.location.nativeElement);

    this.appRef.attachView(dialogRef.hostView);
  }
}

It’s possible to pass an element injector:

export class ToastService {

  constructor(
    private appRef: ApplicationRef,
    private injector: EnvironmentInjector
  ) { }

  open(text: string) {
    const elementInjector = Injector.create({
      providers: [
        {
          provide: 'MyToken',
          useValue: 'Token'
        }
      ],
    });

    const dialogRef = createComponent(ToastComponent, {
      environmentInjector: this.injector,
      elementInjector
    });

    dialogRef.setInput('text', text);

    document.body.appendChild(dialogRef.location.nativeElement);

    this.appRef.attachView(dialogRef.hostView);
  }
}

The component can be appended to a host element:

export class ToastService {

  constructor(
    private appRef: ApplicationRef,
    private injector: EnvironmentInjector
  ) { }

  open(text: string) {
    const dialogRef = createComponent(ToastComponent, {
      environmentInjector: this.injector,
      hostElement: document.getElementById('toasts-container')!
    });

    dialogRef.setInput('text', text);

    this.appRef.attachView(dialogRef.hostView);
  }
}

We can pass projectableNodes — A list of DOM nodes that should be projected through <ng-content> of the new component instance:

openDialog<T>(dialogContent: Type<T>) {
    const footer = document.createElement('p');
    footer.innerText = 'footer';
    
    const dialogContentRef = createComponent(dialogContent, { 
      environmentInjector: this.injector 
    })

    const dialogRef = createComponent(DialogComponent, {
      environmentInjector: this.injector,
      hostElement: document.getElementById('dialog-container')!,
      projectableNodes: [
        // ng-content nodes
        [dialogContentRef.location.nativeElement],
        // second ng-content (e.g <ng-content select="footer"></ng-content>)
        [ footer ]
      ]
    })

    this.appRef.attachView(dialogRef.hostView)
 }

The createComponent API can be used to create components outside components and directives.

Written by Luci
I am a multidisciplinary designer and developer with a main focus on Digital Design and Branding, located in Cluj Napoca, Romania. Profile

Angular Basics: The CLI and Components

Luci in Angular
  ·   7 min read
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x