Angularのフォームとバリデーションを極める!リアクティブvsテンプレート駆動フォーム。
この記事では、Angularのフォームとバリデーションについて実装例とともに解説したい。
入力フォームはWebアプリケーションの開発において要となる要素。Angularを使用する人であれば誰もがフォームを利用することになるだろが、ハマりやすいポイントも結構多いので注意が必要だ。
Angularのフォームコンセプト
まずはAngularにおけるフォームについて確認しよう。
Angularには、簡単に入力フォームなどを作る仕組みが用意されている。
なお、通常のHTMLにもフォームを作成することはできる。
Angularのフォームは2種類ある。
- リアクティブフォーム(Reactive Form)
オブジェクトモデルを主体とするフォーム。こちらのほうがスタンダードに使われる。 - テンプレート駆動フォーム(Template Driven Form)
テンプレートを主体としたフォーム。
リアクティブフォームの使用例
最初によく使用されるリアクティブフォームについて見てみたい。
基本的な実装例
まずは基本的な実装の例から。
以下はユーザ名とメールアドレスを入力するためのフォームだ。
まずはHTML側の実装を見てみよう。
registration.component.html
<form [formGroup]="registrationForm" (ngSubmit)="sendData()">
<div>
<label for="name">ユーザー名:</label><br>
<input id="name" name="name" type="text" [formControl]="name" />
<span *ngIf="name.errors?.required">
ユーザ名は必須項目です。
</span>
</div>
<div>
<label for="mail">メールアドレス:</label><br>
<input id="mail" name="mail" type="email" [formControl]="mail" />
<span *ngIf="mail.errors?.required">
メールアドレスは必須項目です。
</span>
<span *ngIf="mail.errors?.email">
メールアドレスの形式が有効ではありません。
</span>
</div>
<div>
<input type="submit" value="送信" [disabled]="registrationForm.invalid">
</div>
</form>
registration.component.ts
import {Component} from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'app-reactive-form',
templateUrl: './reactive-form.component.html',
styleUrls: ['./reactive-form.component.css']
})
export class ReactiveFormComponent {
public registrationForm: FormGroup;
public name: FormControl;
public mail: FormControl;
constructor(private _builder: FormBuilder) {
this.name = new FormControl('', [Validators.required]);
this.mail = new FormControl('', [Validators.required, Validators.email]);
this.registrationForm = this._builder.group({
name: this.name,
mail: this.mail
})
}
public sendData() {
console.log(this.name.value);
console.log(this.mail.value);
}
}
app.module.tsのimportsにReactiveFormsModuleを追加する。
FormGroup
formGroupはユーザ名やパスワードなどの入力欄を束ねるオブジェクト。
通常は1ページにひとつのFormGroupを使うことが多いが、複数のFormGroupを設置しIDによって区別することもできる。
また入れ子構造としてFormGroup内にFormGroupを設置することもできる。
FormGroupの定義はコンポーネントのTSファイル内でおこなう。
FormControl
FormControlはユーザ名やパスワードといった入力部分に該当する。
FormControlは初期値と使用するバリデーターを決定する。
ひとつのFomControlに複数のバリデーターを設定することもできる。
ngSubmit
ngSubmitはフォームを実行する際のアクションを定義するプロパティ。
デフォルトでENTERキーを押した際にも実行される。
ボタンはデフォルトでsubmitタイプになるので注意が必要だ。
FormArray
複数のFormControlをFormArrayとして使用することもできる。
その際の実装例は以下のようになる。
扱いやすいようにFomrArrayと使用する配列をpublicとして宣言しておく。
public options: FormArray;
public optionArray = ['option1', 'option2', 'option3'];
FormGroup内にあらかじめ空のFormArrayを代入しておいてそこにpush関数を使用してFormControlを動的に追加する。
this.registrationForm = this._builder.group({
options: new FormArray([])
})
this.optionArray.forEach(() =>
(this.registrationForm.controls.options as FormArray).push(new FormControl())
);
HTML側でFormを準備する。ngForで配列をイテレーションさせるといいだろう。
<div formArrayName="options">
<div *ngFor="let opt of optionArray; index as i">
<input [formControlName]="i" placeholder="{{opt}}">
</div>
</div>
各フォームに入力された値を取得する際は以下のようなコードを使用する。
this.options.controls.forEach((value, index) => console.log(array.at(index).value));
フォームを操作する
フォームの操作の方法について説明する。
formの値を取得する
この記事の例では、それぞれのFormControlをひとつのフィールドとして宣言しているので以下のように簡単に値を取得することができる。
this.name.value
FormGroupから入力された値を取得する際は以下のようなコードを使用する。
this.registrationForm.controls.mail.value
値をリセットする
入力した値をプログラムでリセットする際はreset関数を使用する。
this.registrationForm.reset();
FormGroupにControlを動的に追加する
FormGroupにControlを動的に追加することもできる。
this.registrationForm.addControl('pass', new FormControl('', [Validators.required, Utils.passValidator]));
バリデーターの設定
バリデーターはユーザが入力した値が有効であるかをチェックするために存在する。
以下のような場面で使用される。
- 必須項目がすべて入力されているか?
- 入力された値が有効であるか?
- 入力されたemailが規則に則しているか?
値が有効ではない場合はメッセージを表示したり、入力枠の色を変更する。
Angularでこうしたバリデーションをおこなうための機能が備わっている。
代表的なバリデーターには以下のものがある。
バリデーター | 条件 |
---|---|
required | 入力が行われているか? |
pattern(regex) | 指定したRegexのパターンか? |
有効なメールアドレスか? | |
minLength | 指定した文字数以上か? |
maxLength | 指定した文字数以下か? |
またカスタムのバリデーターを自分で作成することもできる。