ngFormを使用してテンプレート駆動フォームを作る

アプリケーションでは、アカウントの作成・ログインなど、フォームを開発する場面が多いかと思います。
今回はAngularのプロジェクトでngFormを使用したテンプレート駆動フォームを実装について整理していこうと思います。

## テンプレート駆動フォームとは
Angularでフォームを実装する手段の一つです。
フォームの実装手段としては、もう一つ「リアクティブフォーム」という方法がありますが、今回はそちらにはあまり触れません。（またどこかで整理したいと思います。）
今回はテンプレート駆動フォームでのフォームの実装方法について整理していこうと思います。

## 作成するサンプルページ
下記のようなシンプルなページを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512668/27564f4b-c003-ce57-d2be-6bc4ee7bd6fe.png)

実装済みのソースコードは以下ですので参考にしていただければと思います。
https://github.com/Nkot117/sample-NgForm

## 準備
### FormsModuleの導入
テンプレート駆動フォームで必要になるFormsModuleの導入します。
``` app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; //追加

import { AppComponent } from './app.component';
import { UserFormComponent } from './user-form/user-form.component';

@NgModule({
  declarations: [AppComponent, UserFormComponent],
  imports: [BrowserModule, FormsModule], // FormsModuleを追加
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
```
### テンプレートの準備
サンプルページのテンプレートを作成します。
ngFormを使用したフォームの実装は後々の手順でやるので、ここでは一旦シンプルなフォームのみ作成します。
``` user-form.component.html
<div class="container">
  <h1>ユーザー情報入力フォーム</h1>
  <form>
    <div class="form-group">
      <label for="name">名前</label>
      <input name="name" type="text" class="form-control" id="name" required minlength="2" />
    </div>
    <div class="form-group">
      <label for="email">メールアドレス</label>
      <input name="email" type="email" class="form-control" id="email" required pattern="^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$"/>
    </div>
    <button type="submit" class="btn btn-success">送信する</button>
  </form>
</div>
```

以上で準備はOKです。次から色々実装していこうと思います。


## フォームに入力した内容を送信する
フォームに入力した内容を取得し、送信できるようにしていこうと思います。
まずはformタグにて、
①ngFormディレクティブをテンプレート変数に代入
②「送信する」ボタンを押下した際に実行する関数の設定を行います。

``` user-form.component.html
<div class="container">
  <h1>ユーザー情報入力フォーム</h1>
  <form　 #userForm="ngForm"　(ngSubmit)="submit(userForm)"> // ここを編集
    <div class="form-group">
      <label for="name">名前</label>
      <input name="name" type="text" class="form-control" id="name" required minlength="2" />
    </div>
    <div class="form-group">
      <label for="email">メールアドレス</label>
      <input name="email" type="email" class="form-control" id="email" required pattern="^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$"/>
    </div>
    <button type="submit" class="btn btn-success">送信する</button>
  </form>
</div>
```
#userForm="ngForm"　で行なっているのが、①のngFormディレクティブをテンプレート変数に代入になります。
(ngSubmit)="submit(userForm)"で行っているのが②「送信する」ボタンを押下した際に実行する関数の設定を行います。
「送信する」ボタンをタップした際には、コンポーネント側で定義するsubmit関数をngFormディレクティブをテンプレート変数のuserFormを引数に設定して実行するように設定しています。

あとは、各inputタグの入力値を双方向でバインドするように設定します。
``` user-form.component.html
<div class="container">
  <h1>ユーザー情報入力フォーム</h1>
  <form　 #userForm="ngForm"　(ngSubmit)="submit(userForm)"> 
    <div class="form-group">
      <label for="name">名前</label>
      <input [(ngModel)]="user.name" name="name" type="text" class="form-control" id="name" required minlength="2" /> // ここを編集
    </div>
    <div class="form-group">
      <label for="email">メールアドレス</label>
      <input [(ngModel)]="user.email" name="email" type="email" class="form-control" id="email" required pattern="^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$"/> // ここを編集
    </div>
    <button type="submit" class="btn btn-success">送信する</button>
  </form>
</div>
```
以上でテンプレート側の実装は完了です。
あとはロジック側に「送信する」ボタンタップ時に実行されるsubmit関数を定義してみます。

``` user-form.component.ts
import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { User } from '../user';

@Component({
  selector: 'app-user-form',
  templateUrl: './user-form.component.html',
  styleUrls: ['./user-form.component.scss']
})
export class UserFormComponent implements OnInit {
  public user: User = new User("","")
  public showErrorMessage: boolean = false;
  constructor() {}
  ngOnInit(): void {
    console.log('UserFormComponent@ngOnInit');
  }

  public submit(form: NgForm): void{
    alert(`名前：${form.value}\nメールアドレス：${form.value}`)
  }
}
```
上記のsubmit関数が「送信する」ボタンタップ時に実行されます。
テンプレート側の入力値はform.value.(inputタグのname属性に設定した名前)で取得することができます。
今回はどこかへの送信は行いませんが、入力値が取得できているか確認できるようにalertで確認できるようにしています。
実行するとこんな感じで入力値がコンポーネント側で取得できていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512668/60954b7b-8538-9ca1-5745-0f3dea2a3253.png)

## まとめ
Angularでフォームを実装する手段の一つであるテンプレート駆動フォームを実装してみました。
記事では整理できていませんが、バリデーションチェックも簡単に実装できます。（サンプルコードは少し実装しているので、気になったら確認してもらえると嬉しいです。）
「リアクティブフォーム」についてもどこかで整理したいなと思っています。