この記事ではAngularの『@Outputデコレーター』について、
- Angularの「@Outputデコレーター」とは
- Angularの「@Outputデコレーター」の使い方
- 子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるように設定する方法
などを図を用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。
Angularの「@Outputデコレーター」とは
Angularでは、親コンポーネントと子コンポーネントの間で値を共有するために、「@Inputデコレーター」と「@Outputデコレーター」を使用します。
- @Inputデコレーター
- 親コンポーネントから子コンポーネントに値を渡すときに使用します。
- @Outputデコレーター
- 子コンポーネントで発生した特定のイベント(例えば、ボタンのクリックなど)を親コンポーネントに通知するときに使用します。
- イベント通知とともに、子コンポーネントから親コンポーネントに値を渡します。
この記事では「@Outputデコレーター」の使い方を説明します。
Angularの「@Outputデコレーター」を用いて作るアプリケーション
この記事では、上図に示すようなアプリケーションをAngularの「@Outputデコレーター」を用いて作成します。
このアプリケーションでは、「子コンポーネントChildComponent」にある「Send Messageボタン」をクリックすると、「親コンポーネントAppComponent」にイベントを通知するとともに、「Hello Parent!!という値(文字列)」を渡します。また、「親コンポーネントAppComponent」では、受け取った「Hello Parent!!という値(文字列)」を画面に表示しています。
作成したアプリケーションの「ディレクトリ構成」
ディレクトリ構成を以下に示します。アプリを作成するためには、★マークで示したファイルを作成する必要があります。
Output-app //アプリ名
├─src
│ ├─app
│ │ ├─app.module.ts //★Appモジュール
│ │ ├─app.component.ts //★親コンポーネント
│ │ └─child.component.ts //★子コンポーネント
│ ├─main.ts
│ ├─index.html
│ └─styles.css
├─angular.json
├─package-lock.json
├─package.json
├─tsconfig.app.json
├─tsconfig.json
└─node_modules
Angularの「@Outputデコレーター」の使い方
Angularの「@Outputデコレーター」を使用する手順を以下に示します。
Angularの@Outputデコレーターを使用する手順
- 子コンポーネントを作成する
- 親コンポーネントを作成する
- Appモジュールに親コンポーネントと子コンポーネントを設定する
上記の手順について、順番に説明します。
子コンポーネントを作成する
以下のプログラムは、今回作成した子コンポーネントの一例です。
//OutputとEventEmitterをインポートする
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<button (click)="sendMessage()">Send Message</button>
`
})
export class ChildComponent {
//@Outputデコレーターを用いてイベントを宣言する
@Output() messageFromChild = new EventEmitter<string>();
sendMessage() {
//emitメソッドを用いて、親コンポーネントにイベントを通知するとともに、値を渡す。
//下記では、ボタンクリック時にmessageFromChildイベントが発生し、
//$eventにstring型の「Hello Parent!!」を渡している。
this.messageFromChild.emit('Hello Parent!!');
}
}
子コンポーネントの作成は以下の手順で行います。
子コンポーネントの作成手順
- 「Output」と「EventEmitter」をインポートする
- 「@Outputデコレーター」を用いてイベントを宣言する
- 「emitメソッド」を用いて、親コンポーネントにイベントを通知するとともに、値を渡す
上記の手順について、順番に説明します。
1-1. 「Output」と「EventEmitter」をインポートする
import { Component, Output, EventEmitter } from '@angular/core';
「子コンポーネントChildComponent」で「@Outputデコレーター」と「emitメソッド」を使用するためには、上記のプログラムのように「Output」と「EventEmitter」をインポートします。
1-2. 「@Outputデコレーター」を用いてイベントを宣言する
@Output() messageFromChild = new EventEmitter<string>();
次に、「@Outputデコレーター」を用いてイベントの宣言をします。以下の構文でイベントを宣言します。
イベントの宣言
@Output() イベント名 = new EventEmitter<$eventに渡すデータの型>();
<...>の部分はイベントが発生した時に「$event」に渡すデータ型を表しています(「$event」は後ほど説明する「親コンポーネントAppComponent」のテンプレートに記述されています)。
「@Outputデコレーター」は、「イベント名」と「親コンポーネントに渡すデータ型」を宣言しているだけです。「親コンポーネントAppComponent」へのイベント通知は、この後に説明する「emitメソッド」で行います。
1-3. emitメソッドを用いて、親コンポーネントにイベントを通知するとともに、値を渡す
//テンプレートでの記述
<button (click)="sendMessage()">Send Message</button>
sendMessage() {
this.messageFromChild.emit('Hello Parent!!');
}
次に、「emitメソッド」を用いて、「親コンポーネントAppComponent」にイベントを通知するとともに、値を渡します。「emitメソッド」の構文を以下に示します。
emitメソッドの構文
this.イベント名.emit($eventに渡すデータ)
上記のプログラムでは、ボタンがクリックされると、「sendMessageメソッド」が実行されます。
「sendMessageメソッド」の中では、「emitメソッド」が実行されています。
「emitメソッド」が実行されると、「親コンポーネントAppComponent」に「messageFromChildイベント」が通知されます。また、「emitメソッド」の引数「'Hello Parent!!'」を「親コンポーネントのテンプレートに記述されている$event」に渡しています。
注意点
「emitメソッドの引数」と「イベントの宣言にて指定したEventEmitter<...>
の型」は一致しなければなりません。
上記のプログラムでは、「this.messageFromChild.emit('Hello Parent!!');
」と「@Output() messageFromChild = new EventEmitter<string>();
」になっており、String型で一致していることが分かります。
親コンポーネントを作成する
以下のプログラムは、今回作成した親コンポーネントの一例です。
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h2>Message from Child: {{ childMessage }}</h2>
<app-child (messageFromChild)="onMessageFromChild($event)"></app-child>
`
})
export class AppComponent {
childMessage: string | undefined;
onMessageFromChild(message: string) {
this.childMessage = message;
console.log("子コンポーネントから値を受け取りました");
}
}
子コンポーネント(ChildComponent)を呼び出すために、子コンポーネント(ChildComponent)のセレクタ(ここでは、app-child)を親コンポーネント(AppComponent)のテンプレートの要素に使用します。
親コンポーネントのテンプレートに記述する構文を以下に示します。
親コンポーネントの構文
<子コンポーネントのセレクタ名 (イベント名)="メソッド名($event)"></子コンポーネントのセレクタ名>
また、上記のプログラムの「(messageFromChild)="onMessageFromChild($event)
」はイベントバインディングの構文であり、「子コンポーネントChildComponent」の「messageFromChildイベント」が発生したタイミングで、「onMessageFromChildメソッド」が呼び出されることを意味しています。
また、「$event」は「子コンポーネントChildComponent」にて記述した「emitメソッド」の引数である「'Hello Parent!!'」となります。
ポイント
「onMessageFromChildメソッド」は「子コンポーネントChildComponent」が発火(emit)した「messageFromChildイベント」を処理する「イベントハンドラー」です。
「子コンポーネントChildComponent」で「messageFromChildイベント」が発火(emit)すると、このイベントハンドラー(onMessageFromChildメソッド)が呼び出され、適切な処理(この場合は、受け取ったメッセージを画面に表示)が実行されます。
モジュールに親コンポーネントと子コンポーネントを設定する
以下のプログラムは、今回作成したAppModuleモジュールの一例です。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ChildComponent } from './child.component'; //追加
@NgModule({
declarations: [
AppComponent,
ChildComponent //追加
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Angularアプリはモジュールから成り立っています。そのため、モジュールにはAngularアプリを構成するコンポーネントやサービスを登録する必要があります。
「親コンポーネントAppComponent」はデフォルトでAppModuleモジュールに登録されています。しかし今回、新たに「子コンポーネントChildComponent」を作成したので、これをAppModuleモジュールに登録する必要があります。
子コンポーネントをAppModuleモジュールに登録するには以下の手順で行います。
子コンポーネントをAppModuleモジュールに登録する手順
- 子コンポーネントをインポートする
- 子コンポーネントを@NgModuleデコレーターのdeclarations配列に追加する
上記の手順について、順番に説明します。
3-1. 子コンポーネントをインポートする
import { ChildComponent } from './child.component';
まず、上記に示すように「子コンポーネントChildComponent」をインポートします。
3-2. 子コンポーネントを@NgModuleデコレーターのdeclarations配列に追加する
@NgModule({
declarations: [
AppComponent,
ChildComponent //追加
],
})
次に、「子コンポーネントChildComponent」を@NgModuleデコレーターのdeclarations配列に追加します。これにより、「子コンポーネントChildComponent」がAppModuleモジュールに登録されます。
以上で準備が完了です。では実際にアプリを実行してみましょう。実行結果は以下のようになります。
プログラムの実行結果
「Send Messageボタン」をクリックすると、「Hello Parent!!」が画面に表示されます。
また、これまで説明したプログラムにおいて、「親コンポーネントAppComponent」と「子コンポーネントChildComponent」の関係を図で表すと以下のようになります。
子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるように設定する方法
今まで説明したプログラムでは、「子コンポーネントChildComponent」のプロパティ名は以下のように記述しているので「messageFromChild」です。
@Output() messageFromChild = new EventEmitter<string>();
また、「親コンポーネントAppComponent」のイベント名も以下のように記述しているので「messageFromChild」です。
<app-child (messageFromChild)="onMessageFromChild($event)"></app-child>
このように、今まで説明したプログラムでは子コンポーネントの「イベント名」と親コンポーネントの「イベント名」が等しくなってます。
では、子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるようにしたい場合には、どのようにすればよいでしょうか。
以下に示すように@Outputデコレーターに引数を渡すことで、子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるようにできます。
@Output('hogehoge') messageFromChild = new EventEmitter<string>();
上記のプログラムでは、「子コンポーネントChildComponent」の「messageFromChildプロパティ」に対応するイベント名は「hogehoge」であると宣言しています。
この場合、「親コンポーネントAppComponent」では、以下のようにイベント名を「hogehoge」にしても正常に動作します。
<app-child (hogehoge)="onMessageFromChild($event)"></app-child>
補足
@Outputデコレーターに引数がない場合には、イベント名とプロパティ名が等しくなります。そのため、以下の記述はどちらも同じ意味となります。
@Output() messageFromChild = new EventEmitter<string>();
@Output('messageFromChild') messageFromChild = new EventEmitter<string>();
本記事のまとめ
この記事ではAngularの『@Outputデコレーター』について、以下の内容を説明しました。
- Angularの「@Outputデコレーター」とは
- Angularの「@Outputデコレーター」の使い方
- 子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるように設定する方法
お読み頂きありがとうございました。