コンテンツへスキップ
Angularでコンポーネントを動的に作成する方法

Angularでコンポーネントを動的に作成する方法

この記事では、コンポーネントを動的に作成する方法を学習します。ポップアップモーダルを表示したい場合など、さまざまなシナリオでコンポーネントを動的にロードする必要がある場合があります。

4min read

以下にリストされているコンポーネントがあり、動的にロードすると仮定します。

import { Component, Input } from '@angular/core';
 
@Component({
    selector: 'app-message',
    template: `<h2>{{message}}</h2>
`
})
export class MessageComponent {
    @Input() message: string;
}

MessageComponentを動的にロードするには、コンテナーが必要です。AppComponent内にMessageComponentをロードするとします。AppComponentにコンテナ要素が必要です。

Template of AppComponent is as below:

<div style="text-align:center">
     <h1>
         Welcome to {{ title }}!
     </h1>
     <template #messagecontainer>
     </template>
 </div>

ご覧のとおり、MessageComponentを動的にロードするエントリポイントテンプレートまたはコンテナテンプレートがあります。

AppComponentでは、以下をインポートする必要があります。

  1. ViewChild、ViewContainerRef、および ComponentFactoryResolver を @angular/core から取得
  2. @angular/core からの ComponentRef と ComponentFactory
  3. message.component からの MessageComponent

必要なものをインポートすると、AppComponnetは次のようになります。

import {
    Component,
    ViewChild,
    ViewContainerRef,
    ComponentFactoryResolver,
    ComponentRef,
    ComponentFactory
} from '@angular/core';
import { MessageComponent } from './message.component';
 
@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})
export class AppComponent {
    title = 'app';
}

Componentクラス内のViewChildとしてテンプレートにアクセスできます。テンプレートは、コンポーネントを動的にロードするコンテナです。したがって、ViewConatinerRefとしてテンプルにアクセスする必要があります。

ViewContainerRefは、1 つ以上のビューをアタッチできるコンテナを表します。これには、2 種類のビューを含めることができます。

  1. Host Views
  2. Embedded Views

ホストビューはcreateComponentを使用してコンポーネントをインスタンス化することによって作成され、埋め込みビューはcreateEmbeddedViewを使用して埋め込みテンプレートをインスタンス化することによって作成されます。ホスト ビューを使用して、MessageComponent を動的にロードします。

テンプレート要素を参照するentryという変数を作成しましょう。さらに、コンポーネントを動的にロードするために必要なコンポーネントクラスにComponentFactoryResolverサービスを挿入しました。

export class AppComponent {
    title = 'app';
    @ViewChild('messagecontainer', { read: ViewContainerRef }) entry: ViewContainerRef;
    constructor(private resolver: ComponentFactoryResolver) { }
}

テンプレート要素の参照であるエントリ変数には、コンポーネントの作成、コンポーネントの破棄などのためのAPIがあることに注意してください。

次に、コンポーネントを作成するために、関数を作成しましょう。関数内で、次のタスクを実行する必要があります。

  • コンテナをクリアする
  • MessageComponent のファクトリを作成する
  • ファクトリを使用してコンポーネントを作成する
  • コンポーネント参照インスタンスメソッドを使用して@Inputプロパティの値を渡す

すべてをまとめると、createComponent関数は以下のリストのようになります。

createComponent(message) {
    this.entry.clear();
    const factory = this.resolver.resolveComponentFactory(MessageComponent);
    const componentRef = this.entry.createComponent(factory);
    componentRef.instance.message = message;
}

ボタンのクリックイベントでcreateComponent関数を呼び出すことができます。テンプレートに2つのボタンを配置し、ボタンをクリックするとcreateComponent関数を呼び出します。

<div style="text-align:center">
    <h1>
        Welcome to {{ title }}!
    </h1>
    <button (click)="createComponent('Welcome Foo ! ')">Welcome</button>
    <button (click)="createComponent('Foo Again ?')">Not Welcome</button>
    <br />
    <template #messagecontainer>
    </template>
</div>

出力では、ボタンをクリックするとコンポーネントが動的にロードされていることがわかります。

 welcome app

ボタンをクリックすると、コンポーネントが別のメッセージでリロードされます。 componentRef の destroy メソッドを使用してコンポーネントを破棄できます。

destroyComponent() {
    this.componentRef.destroy();
}

関数を手動で呼び出して動的にロードされたコンポーネントを破棄するか、コンポーネントのngOnDestroy()ライフサイクルフック内に配置して、ホストコンポーネントが自動的に破棄されると動的にロードされたコンポーネントも破棄するようにすることができます。

すべてをまとめると、AppComponentは以下のリストのようになります。

import {
    Component,
    ViewChild,
    ViewContainerRef,
    ComponentFactoryResolver,
    ComponentRef,
    ComponentFactory
} from '@angular/core';
import { MessageComponent } from './message.component';
 
@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})
export class AppComponent {
    title = 'app';
    componentRef: any;
 
    @ViewChild('messagecontainer', { read: ViewContainerRef }) entry: ViewContainerRef;
    constructor(private resolver: ComponentFactoryResolver) { }
 
    createComponent(message) {
        this.entry.clear();
        const factory = this.resolver.resolveComponentFactory(MessageComponent);
        this.componentRef = this.entry.createComponent(factory);
        this.componentRef.instance.message = message;
    }
    destroyComponent() {
        this.componentRef.destroy();
    }
}

アプリケーションを実行するこの時点では、AppModuleにentryComponentsを設定していないため、エラーが発生します。以下のリストに示すように設定できます。

import { AppComponent } from './app.component';
import { MessageComponent } from './message.component';
 
@NgModule({
    declarations: [
        AppComponent, MessageComponent
    ],
    imports: [
        BrowserModule
    ],
    providers: [],
    bootstrap: [AppComponent],
    entryComponents: [MessageComponent]
})
export class AppModule { }

コンポーネントをAngularで動的にロードするために必要なのはこれだけです。

この投稿が好きですか?

そして、これで完了です!この投稿が気に入ったら、いいねして共有してください。また、まだチェックしていない方は、インフラジスティックスIgnite UI for Angular、ぜひチェックしてください!50+のマテリアルベースのAngularコンポーネントがあり、高速なWebアプリをより速くコーディングするのに役立ちます。

デモを予約