【Angular】@Outputデコレーターの使い方をわかりやすく解説!

この記事ではAngularの『@Outputデコレーター』について、

  • Angularの「@Outputデコレーター」とは
  • Angularの「@Outputデコレーター」の使い方
  • 子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるように設定する方法

などを図を用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。

Angularの「@Outputデコレーター」とは

Angularの「@Outputデコレーター」とは

Angularでは、親コンポーネント子コンポーネントの間で値を共有するために、「@Inputデコレーター」と「@Outputデコレーター」を使用します。

  • @Inputデコレーター
    • 親コンポーネントから子コンポーネントに値を渡すときに使用します。
  • @Outputデコレーター
    • 子コンポーネントで発生した特定のイベント(例えば、ボタンのクリックなど)を親コンポーネントに通知するときに使用します。
    • イベント通知とともに、子コンポーネントから親コンポーネントに値を渡します。

この記事では「@Outputデコレーター」の使い方を説明します。

Angularの「@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モジュールに登録されます。

以上で準備が完了です。では実際にアプリを実行してみましょう。実行結果は以下のようになります。

プログラムの実行結果

Angularの「@Outputデコレーター」の使い方01

「Send Messageボタン」をクリックすると、「Hello Parent!!」が画面に表示されます。

また、これまで説明したプログラムにおいて、「親コンポーネントAppComponent」と「子コンポーネントChildComponent」の関係を図で表すと以下のようになります。

Angularの「@Outputデコレーター」の使い方02

子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるように設定する方法

今まで説明したプログラムでは、「子コンポーネント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デコレーター」の使い方
  • 子コンポーネントの「プロパティ名」と親コンポーネントの「イベント名」を異なるように設定する方法

お読み頂きありがとうございました。