angular 動 的 コンポーネント

Angular 動的コンポーネントの作成と活用法

概要

この文章では、Angularフレームワークを使用して動的コンポーネントを作成する方法を詳しく解説します。動的コンポーネントは、アプリケーションの柔軟性と再利用性を高めるための強力な手法です。

Angularで動的にコンポーネントを追加する

ボタンをクリックした時に、Angularコンポーネントを動的に挿入する方法を記載します。

以下の2つに分けて解説しています。

  • Angularコンポーネントを動的に挿入(→ まずは場所を考えずに挿入します。)
  • 特定の場所に、Angularコンポーネントを動的に挿入

Step1. Angularコンポーネントを動的に挿入

動的に挿入するコンポーネントを作成

ここでは、以下のようなとても簡単なコンポーネントを作成します。

src/app/dynamic/dynamic.component.ts


import { Component } from '@angular/core';

@Component({
selector: 'app-dynamic',
template: `<p>dynamic works!</p>`
})
export class DynamicComponent {

}

ボタンをhtml上に配置

ボタンをクリックすると、メソッド onButtonClick() が実行され、Angularコンポーネントを生成できるようにします。

src/app/app.component.html


<div>
<button (click)="onButtonClick()">click!</button>
</div>

動的にAngularコンポーネントを挿入

ComponentFactoryviewContainerRef を利用し、Angularコンポーネントを挿入します。

  • 初期処理 ngOnInit() で、動的に DynamicComponent をコンパイルできる状態にします。
  • クリックされた時に、 viewContainerRef.createComponent を利用し、コンポーネント生成を実行します。

src/app/app.component.ts


import { Component, ComponentFactory, ComponentFactoryResolver, OnInit, ViewContainerRef } from '@angular/core';
import { DynamicComponent } from './dynamic/dynamic.component';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
factory: ComponentFactory<DynamicComponent>;

constructor(
public viewContainerRef: ViewContainerRef,
private resolver: ComponentFactoryResolver) { }

ngOnInit() {
this.factory = this.resolver.resolveComponentFactory(DynamicComponent);
}

onButtonClick() {
this.viewContainerRef.createComponent(this.factory);
}
}

@NgModule.entryComponents に、動的に挿入するコンポーネントを追加

(3)まで実装し、ボタンをクリックすると、ERROR Error: No component factory found for DynamicComponent. Did you add it to @NgModule.entryComponents? というエラーが表示されます。

指示される通りに entryComponents を追加すると、ボタンを押すと動的にAngularコンポーネントを表示するところまで完成します。

src/app/app.module.ts


import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DynamicComponent } from './dynamic/dynamic.component';


@NgModule({
declarations: [
AppComponent,
DynamicComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent],
entryComponents: [DynamicComponent] // Add entryComponents here!
})
export class AppModule { }

Step2. 特定の場所に、Angularコンポーネントを動的に挿入

(Step1 が完了している前提で) @ViewChild を利用することで、コンポーネントを置く場所を指定することが可能になります。component.tshtmlをそれぞれ編集します。

src/app/app.component.ts


export class AppComponent implements OnInit {
factory: ComponentFactory<DynamicComponent>;
// @ViewChild を追加
@ViewChild('dynamic', { read: ViewContainerRef }) viewContainerRef: ViewContainerRef;

// 不要になった ViewContainerRef をコンストラクタから削除
constructor(
private resolver: ComponentFactoryResolver) { }

(以下略)

htmlには、コンポーネントを挿入したい箇所に、上記の @ViewChild 定義した #dynamic タグを追加します。以下では、ボタンの上にコンポーネントが生成されるようにします。

src/app/app.component.html


<div #dynamic></div>
<div>
<button (click)="onButtonClick()">click!</button>
</div>

上記を完了したうえでボタンをクリックすると、ボタンの上に"dynamic works!"と表示されることが確認できます。

補足

今回の実装ではDOM要素を追加しているだけなので、DomSanitizerを利用して実装することもできます。
コンポーネントを生成するロジックをServiceクラスに置くことで、ほかのコンポーネントから呼び出すことができるようにできます。詳しくは「参考」に載せているページで確認できます。

注意点

動的コンポーネントを使用する際は、ライフサイクルの管理やメモリリークに注意する必要があります。コンポーネントが不用になった際には適切にクリーンアップを行うことが大切です。

参考文献

タイトル リンク
Angular Documentation https://angular.io/docs
Building Dynamic Components in Angular https://www.example.com

Q&A

Q1: 動的コンポーネントはどのような場面で使うべきですか?

A1: ユーザーの操作に応じて、画面上にコンポーネントを動的に追加したい場合に特に有効です。

Q2: メモリリークを防ぐためにはどうすれば良いですか?

A2: コンポーネントが不要になった際に、明示的にクリーンアップを行い、リファレンスを解放することが重要です。

Q3: 動的コンポーネントを使用する際のパフォーマンスへの影響はありますか?

A3: 適切に管理されていれば影響は少ないですが、不必要に多くのコンポーネントを生成するとパフォーマンスに影響を及ぼす可能性があります。