Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Angular TIPS

Angular TIPS

フォームの状態を監視するには?(ngForm/ngModel)

2018年1月15日

Angularにより拡張されている標準的な<form>/<input>要素を使って、入力の有無を判定したり、サブミット済みかを判定したりと、その状態を監視する方法を説明する。

  • このエントリーをはてなブックマークに追加

【対応バージョン】 Angular 5以降。v5時点で執筆しました。

 別稿「TIPS:入力フォームに検証機能を実装するには?」でも触れたように、AngularではngFormngModelディレクティブを利用することで、入力値の妥当性を検証し、不正な値に対してはエラーメッセージを表示することができます。

 もっとも、ngFormngModelの機能はそれだけではありません。入力の有無を判定したり、サブミット済みかどうかを判定したりすることも可能です。本稿では、Angularのフォームで、その状態を監視するための方法についてまとめます。なお、サンプルとしては、前掲の別稿で利用したものからの差分のみを掲載します。

入力済みかどうかを判定する

 フォーム、または個々の要素が入力済みであるかどうかを判定するには「名前.dirty」「名前.pristine」のように表します。名前は、フォーム、または入力要素の名前です。

 dirtyプロパティはフォーム/要素が変更されている場合にtrueを、pristineプロパティはフォーム/要素が変更されていない場合にtrueを、それぞれ返します(つまり、互いに反対の意味を表すというわけです)。

 pristineプロパティを利用することで、(例えば)フォームに何らかの変更があった場合にのみリセットボタンを有効にする、といった動作を実装できます。以下は、その具体的なコードです。

HTML
<input type="reset" value="リセット"
  [disabled]="myForm.pristine" /> 
何らかの入力後のみ押せるリセットボタン(app.component.ts)
何らかの入力を行うと……

何らかの入力を行うと……

入力前は無効化されていたボタンが、入力後は有効化
入力前は無効化されていたボタンが、入力後は有効化

 フォームが未変更であればdisabled属性をtrueにし、リセットボタンを無効化しているわけです。

エラーメッセージを最初から表示しない

 前掲の別稿のサンプルをそのまま動作した場合、実は、required検証を課した要素でエラーメッセージが最初から表示されてしまいます。

フォーム起動時にエラーメッセージを表示
フォーム起動時にエラーメッセージを表示

 まだ何もしていない状態でエラーメッセージが表示されているのは望ましい状態ではありません。しかし、エラーメッセージ表示のコードに、先ほどのdirtyプロパティによる判定を加えることで、エラーメッセージの初期表示を抑制できます。

HTML
<span [hidden]="!(name.errors?.required && name.dirty)">
  名前は必須です。</span>
入力後にのみエラーメッセージを表示する(app.component.ts)

 これで、入力要素が変更されており、かつ、required検証がエラーの場合にのみエラーメッセージを表示する、という意味になります。一般的には、エラーメッセージの表示に際しては、dirtyプロパティで変更の有無をチェックすべきです。

[Note]

 pristinedirtyによく似たプロパティとして、toucheduntouchedプロパティもあります。こちらは、フォーム/入力要素に一度でもフォーカスしたか、一度もフォーカスしていないかを判定するためのプロパティです。

サブミット済みかどうかを判定する

 ngFormsubmittedプロパティを参照することで、フォームがサブミット済みかどうかを判定できます。submittedプロパティを利用することで、(例えば)サブミット済みの場合は、サブミットボタンを無効化するような仕掛けを実装できます(ごくシンプルな二重送信防止の仕組みです)。

HTML
<input type="submit" value="申込" 
  [disabled]="myForm.invalid || myForm.submitted" />
二重クリックできないサブミットボタン(app.component.ts)

 これで入力に不正な値が混在しているか、一度でもフォームが送信された場合には、disabled属性がtrue(=ボタンが無効化)になります。

送信した後はサブミットボタンが無効化
送信した後はサブミットボタンが無効化

フォームの状態に応じてスタイルを変更する

 Angularでは、フォームの状態をプロパティとして公開しているばかりではありません。以下のようなスタイルクラスを、フォームの状態に応じて着脱します。

スタイルクラス 概要
ng-valid 値が妥当な場合
ng-invalid 値が不正な場合
ng-pristine 値が変更されていない場合
ng-dirty 値が変更された場合
ng-untouched 要素にフォーカスが当たったことがある場合
ng-touched 要素にフォーカスが当たったことがない場合
フォームの状態に関わるスタイルクラス

 これらのスタイルクラスを利用することで、例えば検証エラーが発生した項目だけハイライト表示するような仕組みを簡単に実装できます(ディレクティブ、バインド構文すら不要です)。

TypeScript
@Component({
  selector: 'app-root',
  template: `
  <form #myForm="ngForm" (ngSubmit)="show()">
    ……中略……
  </form>
  `,
  styles: [`
    input.ng-dirty.ng-invalid {
      border-color: #f00;
    }
  `]
})
検証エラー時に入力項目の枠を赤くするコード(app.component.ts)
検証エラーのある項目の枠が赤くなる
検証エラーのある項目の枠が赤くなる

 ng-invalidスタイルだけでなく、ng-dirtyを加えているのは、先ほどと同じ理由です。ng-dirtyがない場合、required検証を課した項目が最初から赤く点灯してしまうので、注意してください。

処理対象:ディレクティブ(Directive) カテゴリ:基本
API:NgForm(ngForm)|NgModel(ngModel) カテゴリ:@angular > forms > DIRECTIVE(ディレクティブ)
API:FormsModule カテゴリ:@angular > forms > CLASS(クラス)
API:@NgModuleデコレーター カテゴリ:ADVANCED > Angular Modules

※以下では、本稿の前後を合わせて5回分(第35回~第39回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Angular TIPS
35. 複数のスタイルプロパティをまとめて操作するには?(ngStyle)

ngStyleディレクティブを使って、要素に対して複数のスタイルプロパティをまとめて設定する方法を説明する。

Angular TIPS
36. 入力フォームに検証機能を実装するには?(form/input)

Angularにより拡張されている標準的な<form>/<input>要素を使って、検証機能付きの入力フォームを実装する方法を説明する。

Angular TIPS
37. 【現在、表示中】≫ フォームの状態を監視するには?(ngForm/ngModel)

Angularにより拡張されている標準的な<form>/<input>要素を使って、入力の有無を判定したり、サブミット済みかを判定したりと、その状態を監視する方法を説明する。

Angular TIPS
38. フォームにラジオボタンのリストを設置するには?

選択肢の中から1つを選択する「ラジオボタンのリスト」を設置するための基本的な方法を解説する。

Angular TIPS
39. フォームにチェックボックスのリストを設置するには?

選択肢の中から複数を選択する「チェックボックスのリスト」を設置するための基本的な方法を解説する。

サイトからのお知らせ

Twitterでつぶやこう!