Angular 4 でマテリアルデザインを使う　データバインディング編

前回の投稿 [Angular 4 でマテリアルデザインを使う](https://qiita.com/TsuyoshiUshio@github/items/71146d3baa45231d8bb6)で、とりあえずインストールまでできたので、次に、データのバインディングをマテリアルデザインを適用しながらやってみたい。

# 最初の落とし穴

Angular4 と マテリアルデザインのインストールのブログはあっても、なかなか、Angular 4 のバインディングと一緒に書いている記事は見当たらなかった。多分みんな慣れているからだろう。マテリアルデザインも、Angular も同時に初心者の人はあまりやらないのかな。そこで、何かを参考に基本的なことをやるわけですが、ここで強烈にはまったのが、プロジェクト間違い。

* [AngularJS Material](https://material.angularjs.org/latest/) というプロジェクトと、[Angular Material](https://material.angular.io/) は全く別のプロジェクトである。

という事実だ。最初間違えて AngularJS Material を参考にコードを書いてたら、モジュールが見つからないとか出てきて、初心者の私は死亡、もう、REACT にしようかなぁとか頭によぎった。エラーをググってみると、「AngularJS Material と、Angular Materialは別プロジェクト」ということが書いてあった。、、、ムッチャややこしいわ。ちなみに、「AngularJS Material」 はどうやら、Angular 1.x向けのよう。だから、我々は、基本的に[Angular Material](https://material.angular.io/) を参考にすると良い。基本的にドキュメントは丁寧なのでわかりやすい。

# フォームの作成

まずは基本的なフォームを作ろうとしている。それをバインディングしてみる。

## "Please add a @NgModule annotation" error

最初にやっていると当たったエラー。JavaScript のエラーは理由がよくわからないのも多いなぁ。

* ["Please add a @NgModule annotation" error in 1.0.4. Works in 1.0.3.](https://github.com/angular/angular-cli/issues/6429)

詳細は上記の記事だけど、具体的には、`tsconfig.json` に `path` のエントリを追加する。angular-cli を使っているプロジェクトだと、[Linked libraries](https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/linked-library.md)というのが必要らしく、コンパイルの時のリンクのパスを`tsconfig.json`に指定する必要がある。このエラーメッセージからは到底わからないのが辛いところ。

```json
    "paths": {
      "@angular/*": [
        "..node_modules/@angular/*"
      ]
    },
```

# インプットフォームの作成

とりあえず、食事を入力するフォームを作ってみる。まずは、ドメインクラスの定義

```ts
export class Food {
    name: string;
    date: Date;
    calorie: number;
    protein: number;
    carb: number;
    fat: number;
    meal_kind: FoodType;
}
```

簡単のため、まずは、名前と日付程度を試してみる。

```ts

@Component({
  selector: 'app-root',
  templateUrl: './food-detail.component.html'
})
export class FoodDetailComponent {
  food: Food;
  constructor() {
    this.food = new Food();
    this.food.name = "Taro";
    this.food.date = new Date();
    
  }

  title = 'Muscle Hack';
}
```

## テキスト入力

テキスト入力を可能にするためには、

* [Input](https://material.angular.io/components/input/overview) 

が参考になる。テキスト入力のコンポーネントを使うためには、上記のページの  `API` に書いている通り、`import {MatInputModule} from '@angular/material';` を追加する。具体的には下記の通り。[前回の記事](https://qiita.com/TsuyoshiUshio@github/items/71146d3baa45231d8bb6)の通り、私は、`material.module.ts` という名前で、マテリアル系のインポートは分離している。

```ts
import { NgModule } from '@angular/core';

import {
  MdButtonModule,
  MdMenuModule,
  MdToolbarModule,
  MdIconModule,
  MdCardModule,
  MatInputModule,
} from '@angular/material';

@NgModule({
  imports: [
    MdButtonModule,
    MdMenuModule,
    MdToolbarModule,
    MdIconModule,
    MdCardModule,
    MatInputModule,
  ],
  exports: [
    MdButtonModule,
    MdMenuModule,
    MdToolbarModule,
    MdIconModule,
    MdCardModule,
    MatInputModule,
  ]
})
export class MaterialModule {}
```

通常の入力フォームはこんな感じでいける。バインディングは、通常の、[Angular](https://angular.io/tutorial) の時と同じ。
私は、[Angular Example - Tour of Heroes: Part 6](https://embed.plnkr.co/?show=preview)とかを参考に書いている。

```html
    <md-form-field class="example-full-width">
        <input mdInput placeholder="Name" name="name" [(ngModel)]="food.name" disabled value="Ushio">
    </md-form-field>
```

これだと、極めてそっけない画面になる。これは悲しい。

<img width="242" alt="Screen Shot 2017-10-01 at 6.47.19 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/9d20d59b-c6bb-6f85-0329-3289ce038eef.png">

もう少し見栄えを良くしたい。じゃあ、とりあえず、ツールバーをつけてみよう。

```html
<md-toolbar colo="primary">
        <span>Msucle Hack</span>
    </md-toolbar>
    <md-form-field class="example-full-width">
        <input mdInput placeholder="Name" name="name" [(ngModel)]="food.name" disabled value="Ushio">
    </md-form-field>

```

<img width="361" alt="Screen Shot 2017-10-01 at 6.49.05 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/cb67bf85-56d0-49a7-cc88-7209dfa91021.png">

ぐぬぬ。地味だ、思った色と違う。なんでや！と思ったけど、単にtypo. `color`

```html
<md-toolbar color="primary">
```
やっと思った色に。

<img width="293" alt="Screen Shot 2017-10-01 at 6.50.48 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/df295169-abd4-10f2-0df8-04465ffc921c.png">

しかし、まだまだ、ダサい、なんかサンプルと違う。そうだカードを入れてみよう。

```html
```

それっぽくなった。

<img width="356" alt="Screen Shot 2017-10-01 at 6.52.29 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/0eee895f-640e-52ab-6368-2a3831abdc59.png">

## Date Picker 

次に Date Picker をつけてみたい。やっぱ日付は、部品があるので使いたい。

* [Datepicker](https://material.angular.io/components/datepicker/overview)

を同じく参考にする。ただし、今回は、このページの `API` で必要とされているモジュール以外にも必要になるモジュールが存在した。
`MdNativeDateModule` だ。同じく、`material.module.ts` の記述はこう変わった。

```ts
import { NgModule } from '@angular/core';

import {
  MdButtonModule,
  MdMenuModule,
  MdToolbarModule,
  MdIconModule,
  MdCardModule,
  MatInputModule,
  MdNativeDateModule,
  MatDatepickerModule,
} from '@angular/material';

@NgModule({
  imports: [
    MdButtonModule,
    MdMenuModule,
    MdToolbarModule,
    MdIconModule,
    MdCardModule,
    MatInputModule,
    MdNativeDateModule,
    MatDatepickerModule,
  ],
  exports: [
    MdButtonModule,
    MdMenuModule,
    MdToolbarModule,
    MdIconModule,
    MdCardModule,
    MatInputModule,
    MdNativeDateModule,
    MatDatepickerModule,
  ]
})
export class MaterialModule {}
```
次に、`food-detail.compent.html` を書き換える


```html
<md-toolbar color="primary">
        <span>Msucle Hack</span>
    </md-toolbar>
    
    <md-card>
    <form class="example-form">
        <md-form-field class="example-full-width">
            <input mdInput placeholder="Name" name="name" [(ngModel)]="food.name" disabled value="Ushio">
        </md-form-field>
        <md-form-field>
            <input mdInput [(ngModel)]="food.date" name="date" [mdDatepicker]="myDatepicker">
            <md-datepicker-toggle mdSuffix [for]="myDatepicker"></md-datepicker-toggle>
            <md-datepicker #myDatepicker></md-datepicker>
        </md-form-field>
    </form>
    </md-card>
```

こちらのハマりどころは、先ほどのライブラリの追加ぐらいで特にない。ちなみに、`md-datepicker-toggle` から、`mdSuffix` を抜くと見栄えがおかしくなるので、`mdSuffix`をつけて、場所を調整すること。

うむ。それっぽい。バインディングもしっかりできている。

<img width="777" alt="Screen Shot 2017-10-01 at 7.02.54 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/0252eb0a-f1e4-98a2-3054-84925933d271.png">

うーん。しかし、日本的には表示が違うかな。ロケールを指定しよう。`material.module.ts` のところに、次の記述を追加。

```ts
  providers: [
    {provide: MAT_DATE_LOCALE, useValue: 'ja-JP'},
  ],
```

もしくは、`food-detail.component.ts` のFoodDetailComponent を次のようにする。

```ts
export class FoodDetailComponent {
  food: Food;
  constructor(dateAdapter: DateAdapter<NativeDateAdapter>) {
    dateAdapter.setLocale('ja-JP');
    this.food = new Food();
    this.food.name = "Taro";
    this.food.date = new Date();
    
  }
```

試すとどちらでも動作した。

<img width="767" alt="Screen Shot 2017-10-01 at 7.17.38 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/2843174e-be4c-c246-a0bb-4267c3e1627b.png">

# まとめ

久々に、JavaScript のフロントエンドを触ったが、やっぱデバッグが面倒だ。デバックメッセージからストレートに意味が取れないことが多い。やっぱり、`npm start` をして、部品を一つ一つ追加していって、動くのを確認する方が良さげ。というのも、何かを追加したら、画面が出なくなってガサーとエラーがはかれるわけだけど、部品ごとに区切らないと、デバッグがしにくい。これがちょっとした学び。

次は、enum を使って、選択肢を作ってみたいな。

# リソース

* [Angular 4 Material Tutorial](https://coursetro.com/posts/code/67/Angular-4-Material-Tutorial)
* [Angular](https://angular.io/docs)
* [Angular Material](https://material.angular.io/)
* ["Please add a @NgModule annotation" error in 1.0.4. Works in 1.0.3.](https://github.com/angular/angular-cli/issues/6429)
* [Angular 4 でマテリアルデザインを使う](https://qiita.com/TsuyoshiUshio@github/items/71146d3baa45231d8bb6)