[Angular] 入門 - 基本編 2 - データバインディング 2

おはようございます、朝6時です・・早いです、そして寒いです。今日はだいぶ冷えるとのことで、冬らしくなってきました。

# 前回からのあらすじ

前回の終わりにて

> コンポーネントからビューのデータバインディングはここまでとして（入門なのでサクッと）、
次はビューからコンポーネントのデータバインディング、イベントバインディングを見てみましょう。

ということで、
前回のコンポーネントからビューへのデータバインディングを見ましたが、今日はビューからコンポーネントへデータを渡すイベントバインディングを見てみます。

早速サンプルアプリを見てみましょ。

# イベントバインディング

## 基本

```html:/ClientApp/src/app/counter.component.html
<h1>Counter</h1>

<p>This is a simple example of an Angular component.</p>

<p>Current count: <strong>{{ currentCount }}</strong></p>

<button (click)="incrementCounter()">Increment</button>
```

ここ→`<button (click)="incrementCounter()">Increment</button>`

ボタンをクリックしたときに`incrementCounter()`を呼ぶ。この部分がイベントバインディングになります。

## イベントの種類
他にも下記のようなイベントも使えます（もっとあるけど抜粋）

|イベント名|イベント|
|:---|:--|
|click|クリックされたとき|
|dblclick|ダブルクリックされたとき|
|focus|要素がフォーカスされたとき|
|keydown|キーを押したとき|
|input|入力内容が変更されたとき|
|select|セレクトされたとき|
|reset|リセットされたとき|
|submit|サブミットされたとき|

イベントバインディングに関しては後ほど、さらに詳しくカバーしていく予定ですが、一旦基本はこの辺りで。

次は双方向バインディングを見てデータバインディング編を終わりとします。

# 双方向バインディング

双方向バインディングは字のごとく、コンポーネント側からもビュー側からもデータをバインディングしあう方法です。

VSのサンプルアプリには事例がないので、新しくビューとコンポーネントを作成します。

全く実用性がありませんが、好きな本の名前を入力して、出力するプログラムを例として書いてみます。

まずはビューから

```html:/ClientApp/src/app/books.component.html
<h1>Book</h1>

<p>Type in name of your favorite book</p>

<form>
  <label for="name">名前: </label>
  <input id="name" name="name" type="text" [(ngModel)]="book.name"/>
</form>

<hr/>
<p>
  You like {{book.name}}
</p>
```

そしてコンポーネント

```typescript:/ClientApp/src/books.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-books-component',
  templateUrl: './books.component.html'
})
export class BooksComponent {
  
  book = { name: 'Bleach 第一巻'} ;
}
```

ここで表記があるように
`<element name="name" [(ngModel)]="property"/>`
が基本構文になっています。このようにコンポーネントで定義してクラスプロパティーを要素にバインディングして利用していくことができます。

## 新しいページを追加
このページを表示するのに、新しく作ったコンポーネントを登録し、ルーティングにも登録する必要があるので、app.module.tsも更新します。ルーティングに関しては後程詳しくカバーします。今は一旦読み通してください。

```typescript:/ClientApp/src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { BooksComponent } from './books/books.component'; //追記

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent,
    BooksComponent //追記
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
      { path: 'books', component: BooksComponent} //追記
    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

左側のナビゲーションメニューにリンクも追記します。アイコンは面倒なので一旦コピペで。

```html:/ClientApp/src/app/nav-menu.component.html
<div class='main-nav'>
    <div class='navbar navbar-inverse'>
        <div class='navbar-header'>
            <button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse' [attr.aria-expanded]='isExpanded' (click)='toggle()'>
                <span class='sr-only'>Toggle navigation</span>
                <span class='icon-bar'></span>
                <span class='icon-bar'></span>
                <span class='icon-bar'></span>
            </button>
            <a class='navbar-brand' [routerLink]='["/"]'>NodejsWebAppAngularTutorial1</a>
        </div>
        <div class='clearfix'></div>
        <div class='navbar-collapse collapse' [ngClass]='{ "in": isExpanded }'>
            <ul class='nav navbar-nav'>
                <li [routerLinkActive]='["link-active"]' [routerLinkActiveOptions]='{ exact: true }'>
                    <a [routerLink]='["/"]' (click)='collapse()'>
                        <span class='glyphicon glyphicon-home'></span> Home
                    </a>
                </li>
                <li [routerLinkActive]='["link-active"]'>
                    <a [routerLink]='["/counter"]' (click)='collapse()'>
                        <span class='glyphicon glyphicon-education'></span> Counter
                    </a>
                </li>
              <li [routerLinkActive]='["link-active"]'>
                <a [routerLink]='["/fetch-data"]' (click)='collapse()'>
                  <span class='glyphicon glyphicon-th-list'></span> Fetch data
                </a>
              </li>
              <!--追記-->
              <li [routerLinkActive]='["link-active"]'>
                <a [routerLink]='["/books"]' (click)='collapse()'>
                  <span class='glyphicon glyphicon-th-list'></span> Favorite Book
                </a>
              </li>
            </ul>
        </div>
    </div>
</div>
```

# アプリケーション実行、見てみる

まずはデフォルトのタイトルが表示されていることを確認します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/241909/cd256d47-b7e3-a0ec-1824-d16375a36a89.png)

テキストボックスの内容を更新すると、同時に下のテキストも更新されることが確認できました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/241909/459c275a-af84-1a69-afae-2e9a20457988.png)

# 次、非同期通信

データバインディングの基本はここで終了です。次回はもう少し実用性のあるアプリケーションを作りたいと思います。入力した値に対して外部のAPIから情報を取得するというアプリケーションを例に非同期通信を見てみたいと思います。

Angular入門としては他にも先にカバーするべき要素はあると思いましたが、まずは実用的な例から入って、後程他のコンポーネント、パイプ、サービス、ルーティング、テストなどなどカバーしていきます。