0からのAngular③


[前回](http://qiita.com/hiyoko/items/6bf42578dd6d990ff79c)の続き
該当するチュートリアルページは[こちら](https://angular.io/tutorial/toh-pt2#expose-heroes)

今回チュートリアルを進めると、以下の画像のところまでできるようになった。
![14b82e74329d8ea89d4fcec292548930.gif](https://qiita-image-store.s3.amazonaws.com/0/45577/e4c1b8e8-fa8f-c3e9-cfc7-1ca67fd24fb1.gif "14b82e74329d8ea89d4fcec292548930.gif")
具体的にできることは以下。

- ヒーローをリストで表示
- 選択したヒーローの詳細をリストの下部に表示
- 選択したヒーローのリストは別のスタイルがあたる


## リストで表示するヒーローを用意。
まずは、最初から表示しておくヒーローをいくつか用意。
→Heroクラスのインスタンスを格納する配列を定数で定義する。
配列の要素の追加や削除は再代入にはあたらないので、定数で🙆
Heroクラスが入る配列という型定義ができるのがよい！
Heroクラスよりも下に定義する必要がある。

```javascript
const HEROES: Hero[] = [
  new Hero(11, 'Mr. Nice'),
  new Hero(12, 'Narco'),
  new Hero(13, 'Bombasto'),
  new Hero(14, 'Celeritas'),
  new Hero(15, 'Magneta'),
  new Hero(16, 'RubberMan'),
  new Hero(17, 'Dynama'),
  new Hero(18, 'Dr IQ'),
  new Hero(19, 'Magma'),
  new Hero(20, 'Tornado')
]
```

コンポーネントにもHEROESを代入する変数`heroes`を定義する。

```js
export class AppComponent  {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero: Hero;
}
```

## heroesをビューに表示する。
10人？体？のヒーローをビューに表示する。
`ngFor`という繰り返しを行うディレクティブを使用する。

```js
<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

```

heroesの要素を取り出して、heroというローカル変数に代入して、liタグの子要素のspanタグ部分を描画する。
ということを、herosの要素の数だけ繰り返す。

## スタイルをあてる
リストを表示するだけでは、味気ないのでスタイルを追加して見た目を良くする。

@Componentの中にtemplateのキーと値と同じ要領で`style`というキーとあてたいスタイルを値として入れる。
stylesは配列の中に文字列を入れていることに注意。
配列である理由は、本来複数のスタイルシートを読み込むためだと思われる。

```js
@Component({
  selector: 'my-app',
  template: `
    <h1>{{title}}</h1>
    <h2>My Heroes</h2>
    <ul class="heroes">
      <li *ngFor="let hero of heroes" (click)="onSelect(hero)" [class.selected]="hero === selectedHero">
        <span class="badge">{{hero.id}}</span> {{hero.name}}
      </li>
    </ul>
    <div *ngIf="selectedHero">
      <h2>{{selectedHero.name}} details!</h2>
      <div><label>id: </label>{{selectedHero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="selectedHero.name" placeholder="name">
      </div>
    </div>
    `,
  styles: [`
    .selected {
      background-color: #CFD8DC !important;
      color: white;
    }
    .heroes {
      margin: 0 0 2em 0;
      list-style-type: none;
      padding: 0;
      width: 15em;
    }
    .heroes li {
      cursor: pointer;
      position: relative;
      left: 0;
      background-color: #EEE;
      margin: .5em;
      padding: .3em 0;
      height: 1.6em;
      border-radius: 4px;
    }
    .heroes li.selected:hover {
      background-color: #BBD8DC !important;
      color: white;
    }
    .heroes li:hover {
      color: #607D8B;
      background-color: #DDD;
      left: .1em;
    }
    .heroes .text {
      position: relative;
      top: -3px;
    }
    .heroes .badge {
      display: inline-block;
      font-size: small;
      color: white;
      padding: 0.8em 0.7em 0 0.7em;
      background-color: #607D8B;
      line-height: 1em;
      position: relative;
      left: -1px;
      top: -4px;
      height: 1.8em;
      margin-right: .8em;
      border-radius: 4px 0 0 4px;
    }
  `]
})
```

## リストのヒーロを選択する
リストのヒーローを選択できるようにする。
選択したヒーローの詳細を画面下部に出すところまでやる。
クリックの対象のliタグにクリックの際の処理を紐付ける。

```js
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
```

続いて、選択されたヒーローを代入するための変数をコンポーネントに定義する。
初期値はないため、Heroクラスであることを定義しておく。

```js
export class AppComponent  {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero: Hero;
  }
}
```

クリックされたときに呼ばれる、onSelectメソッドをコンポーネントに定義する。
クリックされたときに、該当するliタグにバインドされたheroを引き数として受取り、selectedHeroに代入するようにしている。

```js
export class AppComponent  {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero: Hero;

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}
```

元々はheroだったが、selectedHeroになったことでテンプレートを変更する必要がある。

```js
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
  <label>name: </label>
  <input [(ngModel)]="selectedHero.name" placeholder="name"/>
</div>
```

最後に、selectedHeroは型定義のみがされた状態からはじまるので、selectedHeroに値が代入されていないときは、テンプレートが表示されない（DOMに追加されないようにする）
ngIfを使うことで、条件がtrueのときにのみ処理を行うようにする。

```js
<div *ngIf="selectedHero">
  <h2>{{selectedHero.name}} details!</h2>
  <div><label>id: </label>{{selectedHero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="selectedHero.name" placeholder="name"/>
  </div>
</div>
```

## 選択されたヒーローのスタイルを変更する
このままでは、どのヒーローが選択されているのかリスト部分からはわからないので、選択されたヒーローのスタイルが変わるようにする。
元々stylesの中には、selectedクラスに対するスタイルが含まれているので、選択されたliタグにのみselectedクラスが付与されるようにする。

```js
<li *ngFor="let hero of heroes"
  [class.selected]="hero === selectedHero"
  (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
```

## 終わりに
このチュートリアルでできるようになったことは、以下。

- ngForを使ってビューを繰り返し表示する
- ngIfを使って、条件がtrueのときにのみビューを表示する
- [class.付与したいクラス]=条件という形式で条件がtrueのときにクラスを付与する
- クリックイベントに併せて処理を行うようにする

だんだんAngularでできることが増えてきて楽しい(*´ω｀*)