Angularと戯れる②

# はじめに
[Angularチュートリアル：Tour of Heroes](https://v17.angular.jp/tutorial)を読み進めていきます。

# 開発環境
- OS: Windows10
- Nodeバージョン: 18.18.0
- Angular CLI バージョン: 17.3.8
- エディタ: VSCode


# 1. ヒーローエディター
[1. ヒーローエディター](https://v17.angular.jp/tutorial/tour-of-heroes/toh-pt1)を読んでいきます。

## 関連コマンド
### コンポーネント作成
```
ng generate component コンポーネント名
```
コンポーネントを作成したいフォルダに行き、このコマンドを実行することで、新規コンポーネントのフォルダが作成されます。

## ソースコードを読み解いてみる
### インターフェース
#### インターフェースについて
「このオブジェクトはこういう値を持っている」という制限をかけるための手法です。

たとえば、Studentというオブジェクトがあり、それは出席番号を保持するidという変数を持っているとします。

出席番号なので数字が入ってほしいところですが、ここに数字以外の値（"Hello"といった文字列など）が入ってこられると困るわけです。

それを防ぐために、「このオブジェクトはこういう値を持っている」という制限が必要になる場合があり、それを実現するための手段がインターフェースです。

<br>
チュートリアルではnumber型のid、string型のnameを持つHeroインターフェースが定義されています。

```TS:src/app/hero.ts
export interface Hero {
  id: number;     // 識別番号を保持する変数。型はnumber（数字）
  name: string;   // 名前を保持する変数。型はstring（文字列）
}
```

#### インターフェースの利用
インターフェースを定義したからには、当然それを使う人がいる訳です。

```TS:src/app/heroes/hero.component.ts
import { Component } from '@angular/core';
import { Hero } from '../hero';             // Heroインターフェースをimport

@Component({
  selector: 'app-heroes',                    // app-heroesというタグを使うことで、heroコンポーネントの内容を参照できる。
  templateUrl: './heroes.component.html',    // 同フォルダのhtmlファイルを読み込む。
  styleUrls: ['./heroes.component.css']      // 同フォルダのcssファイルを読み込む
})
export class HeroesComponent {
  /*
   * heroオブジェクトを定義。
   * heroの実態はHeroインターフェースであり、その定義に乗っ取ってnumber型のidと、string型のnameを持つ。
   */
  hero: Hero = {
    id: 1,
    name: 'Windstorm'
  }
}
```
利用方法は、ざっくばらんに書くと以下のような感じです。
- インターフェースをimportする。
- オブジェクトの型としてそのインターフェースを指定し、値を初期化。

```HTML:src/app/heroes/hero.component.html
<h2>{{ hero.name }} Detail</h2>
<div><span>id: {{ hero.id }}</span></div>
<div><span>name: {{ hero.name }}</span></div>
```
ts側でデータ構造が変わったので、それを参照するhtmlにも手を加える必要があります。
- ダブルカーリーグレイシスを使って値を表示するのは相変わらず。
- ドットでつなげて「このオブジェクトのこの値」といった具合で記載します。

### 双方向データバインディング
#### 双方向データバインディングについて
```HTML:src/app/heroes/hero.component.html
...
<div>
  <label for="name">Hero name: </label>
  <input id="name" [(ngModel)]="hero.name" placeholder="name">
</div>
```
双方向データバインディングについて、チュートリアルでは以下のような解説がされています。
> [([ngModel](https://v17.angular.jp/api/forms/NgModel))]は、Angularの双方向データバインディング構文です。
> これでhero.nameプロパティをHTMLのテキストボックスにバインドするので、 hero.nameプロパティからテキストボックスへ、テキストボックスからhero.nameプロパティへ、 双方向に データを流すことができます。

双方向データバインディングについて、つまりこういうこと↓ という理解をしました。
![双方向データバインディング.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3873589/17bc50c5-4d6d-2904-84a6-f84ccc89cc9c.jpeg)

1. HeroesComponentが保持しているheroオブジェクトのnameがhtmlに参照される。
1. その値はテキストボックスの値として格納される。
1. テキストボックスの値が変更されると、その値は"hero.name" に格納される。
1. これはつまり、HeroesComponentが保持しているheroオブジェクトのnameの値が更新されるということ。

#### ngModel利用のために必要なこと
[FormsModule](https://v17.angular.jp/api/forms/FormsModule)のインポートが必要です。
app.module.tsについては後述。

```TS:src/app/app.module.ts
import { FormsModule } from '@angular/forms';
...
NgModule({
  imports: [
    ...,
    FormsModule
  ],
  ...
})
...
````

### アプリ構成
#### アプリ構成
![tour-of-heroes_hero-editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3873589/b2e1b3ef-b424-36af-a938-78e8bd2d28b4.png)

ここで、現時点でのアプリ構成を図示するとこのような感じです。
- heroesフォルダ
appフォルダの下にheroesフォルダがあり、そこにheroesコンポーネントのリソースが格納されています（heroes CMPと表記）。
- app-root
app-rootとしているのは、そのようなフォルダが切られているわけではなく、appフォルダ直下にアプリルートのコンポーネントのリソースがあるということを示しています。

土台に部品（heroesコンポーネント）を載せるための記載は、以下のような感じです。
```HTML:src/app/app.component.html
<app-heroes></app-heroes>

<!-- 
app-heroesとは何ぞや？
  →heroes.component.tsのselectorで指定した値と一致
-->
````

#### app.module.ts
ここで注目すべきは<b>app.module.ts</b>です。
開発しているアプリが何を使っているのか（参照しているのか）を記載します。

そのアプリで何が使われているのか、何を参照しているのかという情報を知っているブレーンのような感じでしょうか。

言い方を変えると、たとえ新しいコンポーネントを作って実装したとしても、<b>app.module.tsにそれについての記載がされていないと画面に反映されない</b>ということです。
```TS:src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,        // app.component.tsで定義されているクラス
    HeroesComponent      // heroes.component.tsで定義されているクラス
  ],
  imports: [
    BrowserModule,        // angularが提供している機能
    FormsModule           // angularが提供している機能
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

````
ポイントは以下の通り。
- コンポーネントを作ったらそのクラスをdeclarationsに記載
- 入力フォームなど、angularが提供してくれている機能を使いたい場合はimportsに記載