Angular 4 でマテリアルデザインを使う

Angular 4 で、マテリアルデザインを適用してアプリを作ろうと思ったんだけど、無茶苦茶にハマったので、ちゃんと動く手順をメモしておく。

<img width="1103" alt="Screen Shot 2017-09-26 at 11.06.27 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/4b110bbd-9e63-6e22-0f77-083d859aeb75.png">

# ハマった方法

私は、Angular の初心者なので、何から始めたらいいのかわからず、本に書いてある通り、`quick-start` のリポジトリを元に、material design の npm  を追加しました。すると、バージョン問題が発生するので、ちゃんとバージョンを合わせたり、ライブラリのバージョンが違うので、ディレクトリが違うため、`systems.config.js` にライブラリを追記したりと、色々やりましたが、ライブラリ取得時の404エラーは治ることなく、数時間格闘しましたが無理なので、寝ました。

# うまくいく方法

　しかし、問題は、「quick-start」を元にしているからであって、複雑なことを減らすとうまくいくようです。（特に初心者はいきなりたくさんのことを学べないので）現時点でうまく行った方法をシェアします。

基本的には Resource のコーナーで書いて置いた方法のミックスです。

## Angular CLI を入れる

[Angular CLI](https://cli.angular.io/) を入れます。

```
npm install -g @angular/cli
```

## マテリアルデザインのテンプレートを生成する

[Angular 4 Material Tutorial](https://coursetro.com/posts/code/67/Angular-4-Material-Tutorial) に従って、マテリアルデザインの Angular4 のテンプレートがあるので、それを使います。ライブラリの依存問題は、時間がかかるので楽な方法で。

```
ng new ng4-material
```

## マテリアルデザインのnpm を追加

マテリアルデザインのライブラリを追加していきます。ポイントは、`cdk`を先に追加しないとうまくいきません。

```
$ npm install --save @angular/cdk
$ npm install --save @angular/material @angular/animations
```

`hammerjs` も入れておきます。md-slide-toggle, md-slider, mdTooltipは、hammerjs に依存しているので、入れとく方がいいでしょう。

```
$ npm install --save hammerjs
```

そして、`src/main.ts` に追加しておきます。

```
import 'hammerjs';
```
## ライブラリの組み込み

npm で入れたライブラリを組み込んでいきます。

### style の追加

`src/style.css` にお好みのスタイルを追加します。アイコンも加えてこんな感じで。`body` 以降はオプションですが、最初の二行がポイントです。アイコンを取得するのと、インポートしたマテリアルデザインのテーマをインポートしています。

```css
@import '~https://fonts.googleapis.com/icon?family=Material+Icons';
@import '~@angular/material/prebuilt-themes/indigo-pink.css';

body {
    margin: 0;
    font-family: Roboto, sans-serif;
  }
  
  md-card {
    max-width: 80%;
    margin: 2em auto;
    text-align: center;
  }
  
  md-toolbar-row {
    justify-content: space-between;
  }
  
  .done {
    position: fixed;
    bottom: 20px;
    right: 20px;
    color: white;
  }
```
### index.html

特に何もしなくても大丈夫ですが、アイコンインポートしています。（多分不要）

```html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Ng4Material</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
  <app-root></app-root>
</body>
</html>
```
### Material の追加

`material.module.ts` にまとめて、マテリアル関係のインポートを書いておきます。

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

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

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


### app.module.ts

先ほどのマテリアルデザインのインポートを読み込んでいます。

```ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { MaterialModule } from './material.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    MaterialModule,
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

### app.component.html

あとは、マテリアルデザインを使って、読み込まれる html を作成す流だけ。

```html
<div>
  <md-toolbar color="primary">
    <span><md-icon>mood</md-icon></span>

    <span>Muscke Hack</span>

    <button md-icon-button [md-menu-trigger-for]="menu">
      <md-icon>more_vert</md-icon>
    </button>
  </md-toolbar>
  <md-menu x-position="before" #menu="mdMenu">
    <button md-menu-item>Option 1</button>
    <button md-menu-item>Option 2</button>
  </md-menu>

  <md-card>
    <button md-button>All</button>
    <button md-raised-button>Of</button>
    <button md-raised-button color="primary">The</button>
    <button md-raised-button color="accent">Buttons</button>
  </md-card>

  <span class="done">
    <button md-fab>
      <md-icon>check circle</md-icon>
    </button>
  </span>
</div>
```

あとは実行

```
npm start
```

# まとめ

`ng new ng4-material` のテンプレートを使うとアホみたいに簡単にできました。`quick-start` のテンプレートを使うから酷い目にあったようです。本当は、quick-start は、テストとか色々な環境が揃っているので、こちらを元にしたかったのですが、これなら、こちらを元にして、テストを足した方が楽そうです。

やはり、依存性の問題を解決するのは時間がかかるので、そこに当たらないテンプレートを使った方がいいと感じました。さ、やっとコーディングだ。

# Resource

* [Angular CLI](https://cli.angular.io/)
* [Angular 4 Material Tutorial](https://coursetro.com/posts/code/67/Angular-4-Material-Tutorial)
* [material2/guides/getting-started.md](https://github.com/angular/material2/blob/master/guides/getting-started.md)
* [Getting Started With Angular Material 2](https://alligator.io/angular/angular-material-2/)