テンプレート駆動フォームの作成

ここではテンプレート駆動フォーム (template driven forms) を作成する具体的な方法を示します。

データバインディングテンプレート参照変数 の知識が必要です。

テンプレート駆動フォームの作成手順は次の通りです。

  1. フォームで作成・編集するデータのモデルクラスを作成する。
  2. フォームを制御するためのコンポーネントを作成する。
  3. ルートモジュールにて FormsModule とフォームコンポーネントを取り込む。
  4. テンプレートでフォームを作成する。
    • コントロールには name 属性を設定
    • form にはサブミット時のハンドラを設定 (ngSubmit)="onSubmit()"
    • form にはテンプレート参照変数を設定 #form1="ngForm"
  5. モデルクラスのプロパティとフォームコントロールを 2 方向データバインディングでバインドする。
    • [(ngModel)]="employee.email"
  6. テンプレート参照変数を ngModel に設定する。
    • #email="ngModel"
  7. CSS クラス・バインディングとスタイルバインディングを用いて入力状態 (エラーメッセージ等) に関する UI を制御

コントロールの状態

コントロールのテンプレート参照変数に ngModel を設定することで、コントロールの状態と変数の以下のプロパティが連動します。

True False
値は適切か valid invalid
入力ボックスを触ったか touched untouched
変更があったか dirty pristine

具体例でみてみよう

ここでは実際にフォームを作成してみましょう。出来上がりは次のようなフォームです。

Name と Email は必須入力項目、Nickname は任意としましょう。

尚、ここでは Bootstrap を使いますので、Angular プロジェクトを作成したら Bootstrap を設定してください。

モデルクラスの作成

ここでは従業員 (employee) を登録するフォームを作成するので、モデルクラスとして次の Employee クラスを作成します。

src/app/employee.ts として次を作成します。

export class Employee {

  constructor(
    public name: string,
    public email: string,
    public nickname?: string){}
    
}

フォームコンポーネント作成

次にフォームを制御するフォームコンポーネントを作ります。

src/app/form1.component.ts は次の通り。

import {Component} from '@angular/core';
import {NgForm} from '@angular/forms';
import {Employee} from './employee';

@Component({
  selector: 'form1',
  templateUrl: './form1.component.html'
})
export class Form1Component {
  employee = new Employee('', '', '');

  onSubmit(){
    console.log('Submitted:' + JSON.stringify(this.employee));
  }
}

テンプレートは次の通り。

<form
  class="form-horizontal"
  (ngSubmit)="onSubmit()"
  #form1="ngForm">
  <div class="form-group">
    <label class="col-sm-2 control-label">Name</label>
    <div class="col-sm-5">
      <input
        type="text"
        name="name"
        required
        class="form-control"
        [(ngModel)]="employee.name"
        #name="ngModel">
        <div
          class="alert alert-danger"
          [hidden]="name.valid || name.untouched">
          <span class="glyphicon glyphicon-exclamation-sign"></span> Name is required
        </div>
    </div>
  </div>
  <div class="form-group">
    <label class="col-sm-2 control-label">Nickname</label>
    <div class="col-sm-5">
      <input
        type="text"
        class="form-control"
        name="nickname"
        [(ngModel)]="employee.nickname"
        #nickname>
    </div>
  </div>
  <div class="form-group">
    <label class="col-sm-2 control-label">Email</label>
    <div class="col-sm-5">
      <input
        type="text"
        class="form-control"
        name="email"
        required
        [(ngModel)]="employee.email"
        #email="ngModel">
      <div
        class="alert alert-danger"
        [hidden]="email.valid || email.untouched">
        <span class="glyphicon glyphicon-exclamation-sign"></span> Email is required</div>
    </div>
  </div>
  <div class="form-group">
    <div class="col-sm-offset-2 col-sm-5">
      <button
        type="submit"
        class="btn btn-primary"
        [disabled]="!form1.form.valid">Submit</button>
    </div>
  </div>
</form>

ルートモジュールの編集

src/app/app.module.ts に上で作成した Form1Component を取り込みます。もし、FormsModule がインポートされていなければインポートします。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

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

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

以上でコントロールに関連付けされたテンプレート参照変数のプロパティを用いて、 フォームを制御できるはずです。

入力検証は?

上記では入力検証 (valid か invalid か) という点では、HTML 要素に記述する required 属性に依存しています。

しかし HTML での入力チェックはかなりサポート範囲が広がっており、 minlength などで最低限の文字数チェックなどの簡単なことだけではなく、 pattern 属性で正規表現による入力チェック等も可能になっています。

モデル駆動フォームでカスタムバリデータを実装する前に、HTML5 で可能なことを探るのが賢明です。