【Angular】子コンポーネントに値を渡そう!【props】

ANGULAR

みなさんこんにちは、現役エンジニアのサメハックです

アパレル企業でトップ販売員を経て
未経験からWebエンジニアに転職し、
現在正社員として5年働いています!

Angularの解説シリーズです。

今回は子コンポーネントに値を渡す方法について学んでいきましょう!

駆け出しエンジニアや未経験の方、
また新入社員を指導する先輩社員にとっても
わかりやすいように解説していきます!

この記事を読むと・・・
  • 子コンポーネントに値が渡せる

※PCにnpm、nodeがインストールされている前提で記述します。
 yarn等をお使いの方は読み替えてください。

環境がない人はcodesansboxを使ってね!

作りたいもの

ユーザ名が表示されたボタンをクリックすると、
選択したユーザの情報が表示されるアプリケーションを作ります。


★Vue.jsやReactでいうところのpropsを渡す処理です。

これが今回の完成形だよ!
他のファイルは左上のハンバーガーメニューをクリックして確認してね!

親コンポーネントから子コンポーネントへデータを渡す

親コンポーネントの設定

親コンポーネントから子コンポーネントへデータを渡すには、
子コンポーネント内のタグで以下のような記述をする必要があります。

<子コンポーネント [子コンポーネントへ渡す際のプロパティ名]="渡したいデータ"></子コンポーネント>
受け渡す際のプロパティ名は親子で揃えておくのがポイントだよ!

子コンポーネントの設定

データを受け取るには、@Inputデコレータを設定する”だけ”です。

import { Input } from '@angular/core';

@Input() 親から受け取るプロパティ名: データ型;
ややこしく見えるけど、単純に子のプロパティに親が値を入れているだけだよ!

親子でプロパティ名が違う場合

<子コンポーネント [propsX]="データ"></子コンポーネント>
import { Input } from '@angular/core';

@Input(propsX) 子コンポーネントで扱いたいプロパティ名: データ型;

子コンポーネントに値を渡そう!

インターフェイスの作成

親子どちらのコンポーネントでも使用できるように、
外部ファイルにインターフェイスを設定します。

touch ./src/app/user-detail.ts

user-detail.ts

// ユーザ情報を定義
export interface UserDetail {
  name: string;
  age: number;
  job: string;
  hobby: string;
}

interfaceについて詳しく知りたい方はこちら!

【Angular】interfaceとextends【TypeScript】

親コンポーネントの作成

ng generate component users

users.component.ts

import { Component, OnInit } from '@angular/core';
import { UserDetail } from '../user-detail';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css'],
})
export class UsersComponent implements OnInit {
  constructor() {}

  ngOnInit(): void {}

  // 選択されたユーザー ※子コンポーネントに渡す値
  selectedUser: UserDetail;

  /**
   * クリックされたユーザ情報をthis.selectedUserに入れて子コンポーネントに渡す
   * @param user ユーザ情報
   * 戻り値なし
   */
  userSelect(user: UserDetail): void {
    this.selectedUser = user;
  }

  // Userインターフェイスを型として指定
  user1: UserDetail = {
    name: 'サメハック',
    age: 29,
    job: 'エンジニア',
    hobby: 'ギター',
  };

  // Userインターフェイスを型として指定
  user2: UserDetail = {
    name: 'いぬハック',
    age: 30,
    job: '不動産',
    hobby: 'ランニング',
  };

  // Userインターフェイスを型として指定
  user3: UserDetail = {
    name: 'ねこハック',
    age: 45,
    job: 'アパレル',
    hobby: '旅行',
  };

  userList = [this.user1, this.user2, this.user3];
}

ここでのポイントは、この部分です。

// 選択されたユーザー ※子コンポーネントに渡す値
selectedUser: UserDetail;

/**
* クリックされたユーザ情報をthis.selectedUserに入れて子コンポーネントに渡す
* @param user ユーザ情報
* 戻り値なし
*/
userSelect(user: UserDetail): void {
    this.selectedUser = user;
}

クリックイベントを検知した際に、データを渡すため
selectedUserというプロパティを定義し、
クリックされた際に選択されたユーザデータをselectedUserにセットします。

users.component.html

<!-- ループ処理でuserListを1つずつ取り出す -->
<div *ngFor="let user of userList">
  <!-- クリックされたら、userSelect関数を叩き、引数としてuserデータを渡す -->
  <button (click)="userSelect(user)">{{ user.name }}</button>
</div>
<br />

<!-- 子コンポーネントのuserプロパティにselectedUserを渡す -->
<app-user-detail [user]="selectedUser"></app-user-detail>
これで子コンポーネントのuserプロパティにデータを渡せたよ!

ループ処理とクリックイベントリスナーについて復習したい方はこちら!

【Angular】ループ処理を作ろう!【*ngFor】
【Angular】イベントリスナーを作ろう!【サンプルあり】

子コンポーネントの作成

ng generate component user-detail

user-detail.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { UserDetail } from '../user-detail';

@Component({
  selector: 'app-user-detail',
  templateUrl: './user-detail.component.html',
  styleUrls: ['./user-detail.component.css'],
})
export class UserDetailComponent implements OnInit {
  /**
   * 親コンポーネントから値を受け取るための記述
   * @Input() プロップス名: データ型;
   *
   * UserDetail型のデータをuserというプロップス名で受け取る
   */
  @Input() user: UserDetail;

  constructor() {}

  ngOnInit(): void {}
}
前述したとおり、子コンポーネントでは、@Inputデコレータを設定するだけだよ!
あとは受け取ったuser好きに画面に表示しよう!

user-detail.component.html

<div *ngIf="user; else notSelect">
  名前:{{ user.name }}
  <br />
  年齢:{{ user.age }}
  <br />
  職業:{{ user.job }}
  <br />
  趣味:{{ user.hobby }}
</div>

<ng-template #notSelect>ユーザを選択してください</ng-template>

ちなみに、このように受け取ったデータを元に表示を行う場合
*ngIfの設定はほぼ必須です。

この設定をなくしてしまうと、一見正しく表示されますが、
{{ user.name }}のuserが未定義なので

ERROR TypeError: Cannot read properties of undefined (reading 'name')

というエラーがコンソールに出てしまいます。

elseの設定はなくてもいいよ!

画面に反映させよう!

app.component.html

<app-users></app-users>

これで子コンポーネントにデータを渡すアプリケーションが完成したよ!

まとめ

  • 親コンポーネント.htmlの設定
  • <子コンポーネント [子コンポーネントへ渡す際のプロパティ名]=”渡したいデータ”>
  • 子コンポーネント.tsの設定
  • @Input() 親から受け取るプロパティ名: データ型;

満足いただけたら、1クリックなのでSNSフォローしてもらえると嬉しいです🦈

タイトルとURLをコピーしました