HOWTO · Angular

AngularJS setPristine でフォームをリセット

このチュートリアルでは、AngularJS のフォームコントローラーで `$setPristine()` を呼び出し、フォームと各コントロールの操作状態を pristine に戻す方法を説明します。このメソッドはモデル値を変更しないため、入力値を消去または復元する場合は、モデルを別途更新します。

このページの内容

AngularJS でフォームをリセットするとは、操作状態をリセットすること、フィールドにバインドされた値を変更すること、またはその両方を行うことを意味します。フォームコントローラーの $setPristine() メソッドを呼び出すと、フォームと各コントロールを再び pristine 状態にできます。ただし、untouched 状態にはならず、モデル値も変わりません。入力値を消去または復元したい場合は、モデルを別途更新してください。

pristine 状態、dirty 状態、モデル値を理解する

$setPristine() はメソッドです。一方、$pristine と $dirty は、フォームまたはコントロールが持つ真偽値の状態プロパティです。フォームは最初 pristine 状態です。ユーザーがコントロールの値を変更すると、AngularJS によって、そのコントロールと親フォームが dirty 状態になります。$setPristine() を呼び出すと pristine/dirty 状態はリセットされますが、元の値に戻ったり、モデルが空になったりするわけではありません。

touched 状態は別です。$touched と $untouched はコントロールからフォーカスが外れたかどうかを表し、pristine/dirty は値が変更されたかどうかを表します。$setPristine() は touched 状態をリセットしません。コントロールを untouched に戻す必要もある場合は、フォームの $setUntouched() メソッドを別途呼び出してください。必要がなければ touched 状態には手を加えません。

名前付きフォームコントローラーは、フォームの name に基づいて親スコープに公開されます。以下の例では、アプリケーションコントローラーに controller-as 構文(vm)を使い、フォームコントローラーには $scope.profileForm でアクセスします。入力欄を ng-model でバインドし、フィールドを消去または復元するときは、同じモデルプロパティを使ってください。

$setPristine() でフォーム状態をリセットする

このブラウザー向けのコード例では、フォーム、ボタン、コントローラー、名前付きフォームコントローラーのつながりを示します。ページで AngularJS が読み込まれていることを前提としています。最初のボタンは現在のフィールド値を保ったままフォーム状態をリセットし、2つ目のボタンはモデル値を消去してから状態をリセットします。

このセクションのコードと、コード内に表示されるラベルや出力は英語のままです。

<div ng-app="myApp" ng-controller="FormController as vm">
  <form name="profileForm">
    <label>
      Name
      <input name="name" ng-model="vm.profile.name">
    </label>
    <button type="button" ng-click="vm.resetState()">Mark form pristine</button>
    <button type="button" ng-click="vm.clearAndReset()">Clear and reset</button>
  </form>
</div>
<script>
  angular.module('myApp', []).controller('FormController', function ($scope) {
    var vm = this;
    vm.profile = { name: 'Ada' };
    vm.resetState = function () {
      $scope.profileForm.$setPristine();
    };
    vm.clearAndReset = function () {
      vm.profile.name = '';
      $scope.profileForm.$setPristine();
    };
    vm.restoreAndReset = function () {
      vm.profile.name = 'Ada';
      $scope.profileForm.$setPristine();
    };
  });
</script>

ハンドラーは ng-controller で指定したものと同じ vm インスタンスに定義されており、各ボタンは定義済みのメソッドを呼び出します。AngularJS はフォームのリンク処理後、名前付きフォームコントローラーを $scope から利用できるようにするため、クリックハンドラーから $scope.profileForm.$setPristine() を呼び出せます。resetState() は vm.profile.name を変更しません。clearAndReset() はフォーム状態をリセットする前に、そのモデルプロパティを変更します。別の restoreAndReset() メソッドは保存済みの値を復元する例です。必要に応じてボタンなどのアプリケーション操作から呼び出してください。

モデル値は別途消去または復元する

操作状態のリセットとフィールド値の変更は、それぞれ独立した操作です。現在の値を保つには、モデルに代入せず $setPristine() を呼び出します。値を消去するにはバインドされたプロパティに空文字列を代入し、復元するには保存しておいた値を代入します。値と操作状態の両方をリセットする場合は、上の該当するハンドラーのように、モデルを更新してから $setPristine() を呼び出してください。

以下の単独で実行できる JavaScript シミュレーションは、実行環境に AngularJS がなくても、この2つの操作を示します。モデル化しているのは状態と値の変化だけであり、AngularJS のフォーム実装ではありません。

この例を実行してください。

このセクションのコードと、コード内に表示されるラベルや出力は英語のままです。

const form = {
  $dirty: true,
  $pristine: false,
  $setPristine() {
    this.$dirty = false;
    this.$pristine = true;
  }
};
const model = { name: 'Ada' };
model.name = '';
form.$setPristine();
console.log(JSON.stringify({ name: model.name, pristine: form.$pristine, dirty: form.$dirty }));
{"name":"","pristine":true,"dirty":false}

このシミュレーションでは、model.name = '' を代入すると値が消去され、$setPristine() はモデル化した操作状態のフラグだけを変更します。値を維持する動作を試すには、代入を省略します。保存済みの値を復元する動作を試すには、フラグをリセットする前にその値を代入します。AngularJS アプリケーションでは、ブラウザー向けのコード例に示した実際のモデルプロパティとフォームコントローラーを使用してください。

動作を確認し、よくある誤りを避ける

ハンドラーの実行後、名前付きフォームの $pristine と $dirty プロパティを調べ、vm.profile.name も別途確認します。resetState() を使うと、現在の値を保ったままフォームが pristine 状態になります。clearAndReset() を使うと、値が空になり、フォームが pristine 状態になります。モデルに値を代入するだけでは $setPristine() は呼び出されません。両方の結果が必要なら、両方の操作を行ってください。

pristine/dirty と touched/untouched を同じ状態として扱わないでください。フォーカス状態もリセットする必要がある場合に限り $setUntouched() を使います。$setPristine を状態そのものと呼んだり、誤記された $errror プロパティを検証に使ったりしないでください。必須項目のエラーメッセージには、profileForm.name.$error.required のような正しい検証プロパティを確認します。リセットボタンの type="button" はフォームの送信を防ぎます。この手順では AngularJS に組み込まれているフォームコントローラーを使用するため、フォームディレクティブの置き換えやコントローラーメソッドの上書きは不要です。