ボタンをクリックした時に、Angularコンポーネントを動的に挿入する方法を記載します。
以下の2つに分けて解説しています。
- Angularコンポーネントを動的に挿入(→ まずは場所を考えずに挿入します。)
- 特定の場所に、Angularコンポーネントを動的に挿入
Step1. Angularコンポーネントを動的に挿入
動的に挿入するコンポーネントを作成
ここでは、以下のようなとても簡単なコンポーネントを作成します。
...
import { Component } from '@angular/core';
@Component({
selector: 'app-dynamic',
template: `<p>dynamic works!</p>`
})
export class DynamicComponent {
}
ボタンをhtml上に配置
ボタンをクリックすると、メソッド onButtonClick()
が実行され、Angularコンポーネントを生成できるようにします。
...
<div>
<button (click)="onButtonClick()">click!</button>
</div>
動的にAngularコンポーネントを挿入
ComponentFactory
、 viewContainerRef
を利用し、Angularコンポーネントを挿入します。
- 初期処理
ngOnInit()
で、動的にDynamicComponent
をコンパイルできる状態にします。 - クリックされた時に、
viewContainerRef.createComponent
を利用し、コンポーネント生成を実行します。
...
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コンポーネントを表示するところまで完成します。
...
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.tsとhtmlをそれぞれ編集します。
...
export class AppComponent implements OnInit {
factory: ComponentFactory<DynamicComponent>;
// @ViewChild を追加
@ViewChild('dynamic', { read: ViewContainerRef }) viewContainerRef: ViewContainerRef;
// 不要になった ViewContainerRef をコンストラクタから削除
constructor(
private resolver: ComponentFactoryResolver) { }
(以下略)
htmlには、コンポーネントを挿入したい箇所に、上記の @ViewChild
定義した #dynamic
タグを追加します。以下では、ボタンの上にコンポーネントが生成されるようにします。
...
<div #dynamic></div>
<div>
<button (click)="onButtonClick()">click!</button>
</div>
上記を完了したうえでボタンをクリックすると、ボタンの上に"dynamic works!"と表示されることが確認できます。
ソース全体の確認はこちら
補足
- 今回の実装ではDOM要素を追加しているだけなので、
DomSanitizer
を利用して実装することもできます。 - コンポーネントを生成するロジックをServiceクラスに置くことで、ほかのコンポーネントから呼び出すことができるようにできます。詳しくは「参考」に載せているページで確認できます。