[Angular]コンポーネント間でデータを受け渡す ～InputとOutput編～


復習がてら + Angular v9 を試しながら書いてます。  
親子コンポーネント間のデータの受け渡しを行う。  

Angularプロジェクトの立ち上げから**丁寧**にやっていく。  

## 環境

- Angular： v9.0.4
- Node： v12.16.1
- OS： win32 x64

## 準備：Angularプロジェクト作成 ～ 親子Conponent作成 まで

プロジェクト作成、コンポーネント作成のやり方はAngular公式ドキュメントを確認すればOKなのでコマンドだけのせとく。

``` Powershell

# 新規プロジェクト作成
ng new {プロジェクト名}

# 念のため v9(現時点の最新版) にあげとく
ng update @angular/core @angular/cli

# コンポーネント作成 分かりやすいように親：parentと命名
ng generate component parent

# コンポーネント作成 分かりやすいように子：childと命名
ng generate component child
```

app.component.htmlのテンプレート消して作成したcomponentをのっける

## コンポーネント紐づけ

- root

```html:app.component.html
<app-parent></app-parent>
```

- 親コンポーネント

```html:parent.component.html
<p>吾輩が親コンポーネントである。</p>
<app-child></app-child>
```

- 子コンポーネント

```html:child.component.html
<p>私は子コンポーネントです。</p>
```

確認。

```Powershell
ng serve -o
```

## Input編

親コンポーネントで設定した文字列を子コンポーネントに渡してみよう。

### 子コンポーネント側で親から値を受け取る準備をする

- 子コンポーネント側

```Typescript:child.component.ts
import { Component, OnInit } from '@angular/core';
import { Input } from '@angular/core';  // 追加
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
  @Input() valueFromParent: string;  // 追加
  constructor() { }

  ngOnInit(): void {
  }
}
```

```HTML:child.component.html
<p>
    私は子コンポーネントです。
    親から受け取った値：{{valueFromParent}}
</p>
```

### 親コンポーネントから子に値を渡す

親コンポーネントにあるテキストボックスに値を入力したら子コンポーネントに値を渡す。  

- 親コンポーネント側ですること：
  - テキストボックスをHTMLに置く
  - 入力イベント用意
  - データを送れるように設定する

```html:parent.component.html
<p>吾輩が親コンポーネントである。</p>

<div>
  子に渡したい値：
  <input type="text" (keyup)="inputValue($event)">
</div>

<app-child [valueFromParent]="toChildValue"></app-child>
```

```Typescript:parent.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
  public toChildValue: string; // 子へ送る値を格納する変数を用意
  constructor() { }

  ngOnInit(): void {
  }

  inputValue(event: any) { // without type info
    this.toChildValue = event.target.value;
  }
}
```

完成。

テキストボックスに値を入力すると、keyupに設定したinputValue()メソッドが呼び出される。  
keyup:ユーザーがキーを押して離すのがトリガー。  
※changeイベントでも代用できるよ。  

inputValue()では親コンポーネントのパブリック変数 toChildValue に入力値を代入している。
  
```html:parent.component.html
<app-child [valueFromParent]="toChildValue"></app-child>
```
子コンポーネントで設定した変数 valueFromParentに toChildValueを設定することで、子に値を渡せる。  

## Output編

Outputは子から親に値を返す。  
イメージとしては、親が子のイベントを監視する感じ。  
子コンポーネントで入力した値を親コンポーネントに返そう。  
EventEmitter使います。初めて使う方はこちら→ https://www.whizz-tech.co.jp/1659/ 見ながらのほうが分かりやすくなると思います。

- 親コンポーネント側
  - 子供のイベントを監視するようにする

```HTML:parent.component.html
<p>
  吾輩が親コンポーネントである。子から受け取った値：{{fromChildValue}}
</p>

<div>
  子に渡したい値：
  <input type="text" (keyup)="inputValue($event)">
</div>

<app-child [valueFromParent]="toChildValue"
           (event)="onReceiveEventFromChild($event)">
</app-child>
```

``` Typescript:parent.component.ts
  public fromChildValue: string; // 子から受け取った値を格納する変数を用意

  onReceiveEventFromChild(eventValue: string) {
    this.fromChildValue = eventValue;
  }
```

- 子コンポーネント側
  - Output()デコレータ用意。
  - EventoEmitterインスタンス化。
  - inputこのメソッドinputChildValue()を呼び出す
  - inputChildValue()内で親に返したい値を引数にしてemitメソッドを呼び発火させる。  

```HTML:child.component.html
<p>
    私は子コンポーネントです。
    親から受け取った値：{{valueFromParent}}
</p>

<!-- ↓追加 -->
<div>
    親に渡したい値：
    <input type="text" (keyup)="inputChildValue($event)">
</div>
```

```Typescript:child.component.ts
import { Component, OnInit } from '@angular/core';
import { Input, Output, EventEmitter } from '@angular/core';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
  @Input() valueFromParent: string;
  @Output() event = new EventEmitter<string>(); // 追加
  constructor() { }

  ngOnInit(): void {
  }

  // 追加
  inputChildValue(event: any) {
    this.event.emit(event.target.value);
  }

}

```

完成。  

　子側では、イベントが発火したよとういうのをOutputしてるイメージ。  
親側は、子のイベントを常に監視しているイメージ。
イベントが発火したらonReceiveEventFromChildメソッドを呼び、親の変数に受け取った値を代入している。

## 終わり

次は＠ViewChild＆AfterViewInitを使ったデータの渡し方について復習する予定。  
使いこなせば自在に子コンポーネントを参照し、親コンポーネント内の変数にアクセスできるようになるだろう。

- ＠ViewChild
- AfterViewInit

## 参考

- EventEmitterとは：https://www.whizz-tech.co.jp/1659/