AngularFormsの重要なメソッド解説: markAsTouched()、markAsDirty()、markAsPristine()

2023/06/20に公開

皆さんこんにちは、株式会社エムアイ・ラボの新人エンジニアです!
弊社のメインフレームワークであるAngularのフォームバリデーションで動作に曖昧な部分があり、どんな種類がありどのように動作するのか調べてまとめたので、皆さんに共有できればと思います。

まずは公式ドキュメントで概要から・・・(英文なので適宜Google翻訳しています)

AngularForms(公式ドキュメントから引用)

ユーザー入力を取得するフォームを構築する際に、ネイティブの DOM 要素と通信するためのディレクティブとプロバイダーのセットを実装します。
このAPIを使用して、ディレクティブを登録し、フォームとデータモデルを構築し、フォームにバリデーションを提供します。バリデーターは、ユースケースに応じて、同期または非同期で使用することができます。
また、インターフェースとトークンを使ってカスタムバリデータと入力要素を作成することで、Angularのフォームが提供する組み込み機能を拡張することができます。

私には難しい説明です・・・
曖昧な部分は少しでも無くしたいので、わからない単語と、わかりそうでわからない言葉から調べていきます。

  • ネイティブDOM要素
    ネイティブDOM要素とは、ウェブページの部品であり、それぞれが特定の役割や機能を持っている。
    要素を使って、ウェブページを操作したりすることができる。
    div要素、p要素、img要素、input要素、button要素、a要素のことですね。

  • ディレクティブ
    ウェブページ上の特定の要素に効果を加えることができるもの。
    (例えば、ボタンをクリックしたときにメッセージを表示するディレクティブを作成するなど)

  • プロバイダー
    ここで言うプロバイダーはディレクティブに必要なサポートや情報を提供する役割の意味合いのようです。
    (ディレクティブが動作するために必要なデータや設定をプロバイダーが提供)

ここまで調べると、AngularFormsは、HTMLテンプレートとコンポーネントクラスを組み合わせて、動的なフォームを作成できるということがわかってきます!

AngularFormsのクラス

AngularFormsには以下のクラスがあります

FormControl  
FormControlは、フォーム内の単一の入力要素(input、textarea、selectなど)です。
単一の値の管理とバリデーションを行います。値の設定や取得、バリデーションの設定、状態の追跡などができます。

  
FormGroup  
FormGroupは、複数のフォームコントロールや他のフォームグループをまとめるコンテナです。
入れ子になった形でフォームのセクションを作成し、値の管理やバリデーションを行います。フォーム内の要素にアクセスするためのメソッドやプロパティも提供します。
  
AbstractControl
FormControlとFormGroupの共通クラスです。
値の管理、バリデーション、状態の追跡などの共通の機能を提供します。

FormArray
FormArrayは、フォームコントロール(FormControl)やフォームグループ(FormGroup)を配列として管理するためのクラスです。一連の項目を持つフォームコントロールのコレクションを表します。追加、削除、並べ替えなどの操作を提供します。
これらのクラスを組み合わせて、フォームデータの作成、バリデーション、データの取得や設定、状態の管理などを行うことができます。

各クラスには、様々なメソッドがありますが、今回は共通のメソッド(AbstractControlを継承)の中で、違いの曖昧なmarkAsTouched() markAsDirty() markAsPristine() の三点に絞りこんで違い理解していきたいと思います!

markAsTouched()

ユーザーがフォームコントロールに触れた(操作した)ことを表すためのメソッドです。
これによって、ユーザーがコントロールに触れたが何も入力しなかった場合などの状況を管理できます。

typescript
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
  control = new FormControl('');
  
  onBlur(): void {
    this.control.markAsTouched();
    console.log(this.control.touched); // true
  }
}
html
<input type="text" [formControl]="control" (blur)="onBlur()" />

このコードの処理の流れとしては、ユーザーが入力フィールドに何らかの操作(例えば、文字を入力したり、フォーカスを当てたり)をします。
操作が完了し、ユーザーが入力フィールドからフォーカスを外すとonBlur()メソッドが呼ばれます。
onBlur()メソッドの中でmarkAsTouched()が呼び出され、そのフォームコントロールを"touched"状態とします。その結果("touched"の状態)がtrueでコンソールに出力されます

markAsDirty()

ユーザーがフォームコントロールの値を変更したことを表すためのメソッドです。
フォームの値が初期値から変更された場合を検出できます。

typescript
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
  control = new FormControl('');
  
  onInput(): void {
    this.control.markAsDirty();
    console.log(this.control.dirty); // true
  }
}
html
<input type="text" [formControl]="control" (input)="onInput()" />

このコードの処理の流れとしては、ユーザーがフィールドに何か入力するとonInput()メソッドを呼び出します。
入力が行われるとonInput()メソッドでは、まずmarkAsDirty()が呼び出され、このフォームが"dirty"(ユーザーによって値が変更された)と状態を検知します。
その後、console.log(this.control.dirty);によってその"dirty”その結果は”true”でコンソールに出力されます。

markAsPristine()

フォームコントロールの値が初期状態に戻ったことを表すためのメソッドです。

typescript
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
  control = new FormControl('');
  
  onReset(): void {
    this.control.reset();
    this.control.markAsPristine();
    console.log(this.control.pristine); // true
  }
}
html
<input type="text" [formControl]="control" />
<button (click)="onReset()">Reset</button>

このコードの処理の流れとしては、リセットボタンを押すとonReset()メソッドが呼び出され、入力された値がreset()メソッドでリセットされて、markAsPristine()がフォームコントロールの状態を「初期の状態また」は「変更されていない」状態に設定してくれます。
コンソールにはtrueが出力されます。
ここで、注意点としてはmarkAsPristine()はフォームの状態を変更しますが、実際のフォームコントロールの値は変更しません。

簡単に言えば、markAsTouched()はユーザーがフィールドに触れただけで、markAsDirty()はユーザーがフィールドに触れてその値を変更したことを示します。
どちらのメソッドも、ユーザーの変更状態を検知できますが、markAsDirty()はユーザーが実際にフィールドの値を変更したことを検知するので具体的な状態がわかります。

まとめ

初のテックブログで、しかも初学者の拙い説明でしたので理解していただけたか不安です・・・。
やはり手を動かして挙動を確認するのが、理解すること、学習定着には一番だと思います!

Angularの公式ドキュメントのGetting started with AngularのCreate the product listの項目でStackBlitzで環境構築なしで簡単なAngularアプリが動かせるので今日紹介したフォームの動作確認におすすめです!

ready-made sample project in StackBlitz.
https://stackblitz.com/edit/vq8afr-wvfnmq?file=src%2Fapp%2Fapp.component.ts
また日々実務をする中で、学びや気付きがあれば記事投稿していきたいと思いますので、よろしくお願いいたします!

タイトルについて

この記事のタイトルはChatGPTに考えてもらいました。

採用情報

エムアイ・ラボでは一緒に働くメンバーを募集しています!!
ぜひお気軽にご連絡ください!

https://www.wantedly.com/companies/milab-inc

Discussion