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

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

» 2018年01月15日 05時00分 公開
[山田祥寛]
「Angular TIPS」のインデックス

連載目次

現在では、Web標準技術を利用したアプリ開発が広く普及し、そのためのフレームワークも多数存在しています。その中でも主流のフレームワークの1つである「Angular」を活用し、そのための知識を備えることには大きな意味があります。本連載は、Angularユーザーに向けて、その使いこなしTIPSを紹介するものです。なお、本連載は「Build Insider」で公開していた連載「Angular Tips」を同サイトおよび筆者の了解を得たうえで、本フォーラムに移行したものです。記事はBuild Insiderで公開した状態のまま移行しているため、用語統一などの基準が@ITの通常の記事とは異なる場合があります。


【対応バージョン】

 Angular 5以降。v5時点で執筆しました。


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

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

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

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

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

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

<input type="reset" value="リセット"
  [disabled]="myForm.pristine" /> 

何らかの入力後のみ押せるリセットボタン(app.component.ts)

何らかの入力を行うと……
何らかの入力を行うと……
入力前は無効化されていたボタンが、入力後は有効化 入力前は無効化されていたボタンが、入力後は有効化

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

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

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

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

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

<span [hidden]="!(name.errors?.required && name.dirty)">
  名前は必須です。</span>

入力後にのみエラーメッセージを表示する(app.component.ts)

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

[Note]

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


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

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

<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 要素にフォーカスが当たったことがない場合
フォームの状態に関わるスタイルクラス

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

@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


「Angular TIPS」のインデックス

Angular TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。