Angular – Dynamische Component erzeugen

Tutorial Angular

von Ardian Shala, 20.05.2017
Das Erzeugen einer dynamischen Component in Angular erlaubt das Hinzufügen eines Templates zur Laufzeit und ermöglicht so ein asynchrones Hinzufügen von zuvor nicht deklarierten Componenten und NgModules.
Vorraussetzung:

Dynamische Component App Einstiegspunkt

Das Integrieren einer dynamischen Component wird hier einfachheitshalber direkt in „app.component.ts“ definiert.

//app.component.ts
@NgModule({
    imports: [BrowserModule],
    declarations: [App],
    bootstrap: [App]
})
export class AppModule { }

Dynamische Component

Für Demonstationszwecke reicht eine Funktion „hello“ und eine Property „someText“, welche später in einem Template gebunden werden.
Die dynamische Component könnte wie folgt aussehen.

@Component({ template: dynamicTemplate })
class DynamicComponent {
    hello() {
        alert("hello dynamic component");
    }
    someText = "some text";
}

Diese Component integrieren wir in eine Funktion „compileToComponent“, welche als Parameter das Template erwartet.
Zusätzlich wird ein dynamische NgModule erzeugt, welches die dynamische Component deklariert.

@NgModule({
    imports: [BrowserModule],
    declarations: [DynamicComponent]
})
class DynamicModule { }

ComponentFactory, ViewContainerRef und Compiler

Für das Kompilieren eines dynamischen NgModule werden folgende Services benötigt, die in „app.component.ts“ injected werden müssen:
– ViewContainerRef – erstellt eine Referenz zur dynamisch erzeugten Component
– Compiler – kompiliert asynchron das dynamische Module und seine Components

Funktion createDynamicComponent erstellen

Die Funktion „createDynamicComponent“ soll hier von einem Button-Click getriggered werden und übergibt ein simples Template, welche die oben genannte Funktion „hello“ und das Text Binding „someText“ beinhaltet.

public createDynamicComponent() {
    (this.compileToComponent("<div (click)='hello()'>{{someText}}</div>")).then((factory: ComponentFactory<any>) => {
        this.cmpRef = this.viewContainerRef.createComponent(factory)
    })
}

App Template abändern

Template von App abändern, sodass ein Button integriert wird, der die zuvor erstellte Funktion „createDynamicComponent“ aufruft.

template: `<button (click)="createDynamicComponent()">Create dynamic Component</button>`

Wird nun die App neugestartet / refreshed und der Button „Create dynamic Component“ angeklickt, soll genau einmal die „DynamicComponent“ erzeugt und angezeigt werden.

Finaler Code

import { Component, OnInit, Input, NgModule, NgModuleFactory, Compiler, ComponentFactory, ViewContainerRef } from'@angular/core';
import { BrowserModule } from'@angular/platform-browser';

@Component({
    selector:'my-app',
    template:`<button (click)="createDynamicComponent()">Create The Dynamic Component</button>`
})
export class App {
    constructor(private viewContainerRef: ViewContainerRef, private compiler: Compiler) {
    }

    private cmpRef: ComponentRef<any>;

    public createDynamicComponent() {
        (this.compileToComponent("<div (click)='hello()'>{{someText}}</div>")).then((factory: ComponentFactory<any>) => {
            this.cmpRef = this.viewContainerRef.createComponent(factory)
        })
    }

    private compileToComponent(dynamicTemplate: string): Promise<ComponentFactory<any>> {
        @Component({ template:dynamicTemplate })
        class DynamicComponent {
            hello() {
                alert("hello dynamic component");
            }
            someText = "some text";
        }

        @NgModule({
            imports: [BrowserModule],
            declarations: [DynamicComponent]
        })
        class DynamicModule { }

        return this.compiler.compileModuleAndAllComponentsAsync(DynamicModule).then(
            factory=>factory.componentFactories.find(x=>x.componentType === DynamicComponent)
        )
    }
}

@NgModule({
    imports: [BrowserModule],
    declarations: [App],
    bootstrap: [App]
})
export class AppModule { }

Autor: Ardian Shala

Ersteller der Webseite MuchaDev.
Frontend Entwickler mit Angular, Ionic und Backend Entwickler mit C#.