2019年5月1日水曜日

AngularのEventEmitter(Output、emit) で複数の値を送りたい。


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

令和最初のブログはAngularです。

今回は、普段は意識しないけど、「そう言えばどうやるんだ?」的な小ネタです。

Angularでは、親コンポーネントから子コンポートに値を渡す時は「@Input()」を使用します。
イメージ的には変数経由で値を渡す、と言う感じですかね。
逆に子コンポーネントから親コンポートに値を渡す時は「@Output()」を使用します。
こちらは、メソッドに経由で値を渡す、と言う感じです。

この「@Output()」ですが、簡単な使い方として、
親コンポーネント側(hoge-parent.component.ts)で、以下のように記載します。
分かりやすくする為にView(html)はファイルを分けています。(hoge-parent.component.html)

[hoge-parent.component.ts]
@Component({
  selector: 'koma-hoge-parent',
  templateUrl: './hoge-parent.component.html'
})
export class HogeParentComponent {

// (中略)

  onSubmit(childValue: string) {
    console.log(childValue);
  }
}

[hoge-parent.component.html]
<koma-hoge-child
  (formSubmit)="onSubmit($event)">
</koma-hoge-child>

「onSubmit($event)」が子コンポーネントからの指示(formSubmit)を待ち構えている、と言う表現がしっくりきますね。

子コンポーネント側(hoge-child.component.ts)は、以下のように記載します。
[hoge-child.component.ts]
@Component({
  selector: 'koma-hoge-child',
  templateUrl: './hoge-child.component.html'
})
export class HogeChildComponent {
  @Output() formSubmit = new EventEmitter<string>();

// (中略)

  onClickButton(textValue: string) {
    this.formSubmit.emit(textValue);
  }
}

onClickButton のメソッドの中で、textValue を引数に、「emit」を使って、親コンポーネント側の処理を実行します。

と、前置きが長くなったのですが、上記までが「@Output()」の使い方の基本です。

ある時、ふと思ったんですよね。
あれ?これ、複数の引数を送りたい場合どうするんだ?
と。

モデル(クラス)を利用して複数の値を送る場合

モデル(クラス)を利用すれば、引数としては1つですが、複数の値を送る事が実現できます。
[hoge.ts]
export class HogeHogeModel {
  hogeId: string;
  hoge1: string;
  hoge2: number;
}

[hoge-child.component.ts]
@Component({
  selector: 'koma-hoge-child',
  templateUrl: './hoge-child.component.html'
})
export class HogeChildComponent {
  @Output() formSubmit = new EventEmitter<HogeHogeModel>();

// (中略)

  onClickButton(textValue: string) {
   const hogeObj = new HogeHogeModel();
    hogeObj.hogeId = textValue;
    hogeObj.hoge1 = '名前';
    hogeObj.hoge2 = 1234;
    this.formSubmit.emit(hogeObj);
  }
}

親コンポーネント側(hoge-parent.component.ts)は下記のようになります。
※View(hoge-parent.component.html)は変更不要です。
[hoge-parent.component.ts]
@Component({
  selector: 'koma-hoge-parent',
  templateUrl: './hoge-parent.component.html'
})
export class HogeParentComponent {

// (中略)

  onSubmit(childObj: HogeHogeModel) {
    console.log(childObj.hogeId);
    console.log(childObj.hoge1);
    console.log(childObj.hoge2);
  }
}

記載は省略していますが、モデル(クラス)のimportは必須です。

「モデル(クラス)を送れば解決」でも良いんですが、
わざわざモデル(クラス)を作るのもなぁ・・・・と思う事があるかもしれません。
(個人的にはそれでもモデル(クラス)作るべきだと思いますが)

連想配列をその場で定義し、複数の値を送る場合

ちょっと特殊ですが、もう一つの書き方を紹介します。
子コンポーネント側(hoge-child.component.ts)を以下のように記載します。
[hoge-child.component.ts]
@Component({
  selector: 'koma-hoge-child',
  templateUrl: './hoge-child.component.html'
})
export class HogeChildComponent {
  @Output() formSubmit = new EventEmitter<{ hogeId: string; hoge1: string; hoge2: number }>();

// (中略)

  onClickButton(textValue: string) {
    this.formSubmit.emit({
      hogeId: textValue,
      hoge1: '名前';,
      hoge2: 1234
    });
  }
}

まあ、分かってしまえば、「そりゃそうだよな」と言う書き方なのですが。

続いて、親コンポーネント側(hoge-parent.component.ts)は下記のようになります。
※View(hoge-parent.component.html)は変更不要です。
[hoge-parent.component.ts]
@Component({
  selector: 'koma-hoge-parent',
  templateUrl: './hoge-parent.component.html'
})
export class HogeParentComponent {

// (中略)

  onSubmit(childObj: any) {
    console.log(childObj.hogeId);
    console.log(childObj.hoge1);
    console.log(childObj.hoge2);
  }
}

気を付ける事は引数の型を「any」にする事ぐらいですかね。
型を特定出来ない(any)と言う事は、実行時にエラーになる可能性が高いので、やはりオススメしません。

以上です。今回も内容の割には長くなってしまいました・・・・

では、令和も良いAngularライフを!