web-dev-qa-db-ja.com

すべての検証エラーを削除するなど、フォームをリセットするにはどうすればよいですか?

Angularフォーム。フィールドは_ng-pattern_属性を使用して検証されます。リセットボタンもあります。 Uiを使用しています.Utils Event Binderresetイベントを次のように処理します。

_<form name="searchForm" id="searchForm" ui-event="{reset: 'reset(searchForm)'}" ng-submit="search()">
  <div>
    <label>
      Area Code
      <input type="tel" name="areaCode" ng-model="areaCode" ng-pattern="/^([0-9]{3})?$/">
    </label>

    <div ng-messages="searchForm.areaCode.$error">
      <div class="error" ng-message="pattern">The area code must be three digits</div>
    </div>
  </div>

  <div>
    <label>
      Phone Number
      <input type="tel" name="phoneNumber" ng-model="phoneNumber" ng-pattern="/^([0-9]{7})?$/">
    </label>

    <div ng-messages="searchForm.phoneNumber.$error">
      <div class="error" ng-message="pattern">The phone number must be seven digits</div>
    </div>
  </div>

  <br>
  <div>
    <button type="reset">Reset</button>
    <button type="submit" ng-disabled="searchForm.$invalid">Search</button>
  </div>
</form>
_

ご覧のとおり、フォームがリセットされると、フォームは_$scope_のresetメソッドを呼び出します。コントローラ全体は次のようになります。

_angular.module('app').controller('mainController', function($scope) {
    $scope.resetCount = 0;

    $scope.reset = function(form) {
        form.$setPristine();
        form.$setUntouched();
        $scope.resetCount++;
    };

    $scope.search = function() {
        alert('Searching');
    };
});
_

ここでStack Overflowの 別の質問 からのアドバイスに従って、form.$setPristine()と_form.$setUntouched_を呼び出しています。カウンターを追加した唯一の理由は、コードが呼び出されていることを証明することでした(これが原因です)。

問題は、フォームをリセットした後でも、検証メッセージが消えないことです。完全なコードは Plunker で確認できます。エラーが消えないことを示すスクリーンショットは次のとおりです。

Validation Errors

23
battmanz

@Brettからのコメントから始めて、それに基づいて作成しました。実際には複数のフォームがあり、各フォームには多くのフィールドがあります(表示されている2つだけではありません)。だから私は一般的な解決策が欲しかった。

Angular formオブジェクトには、各コントロール(入力、選択、テキストエリアなど)およびその他のAngular =プロパティ。ただし、各Angularプロパティは、ドル記号($)。だから私はこれをやった(他のプログラマーの利益のためのコメントを含む):

$scope.reset = function(form) {
    // Each control (input, select, textarea, etc) gets added as a property of the form.
    // The form has other built-in properties as well. However it's easy to filter those out,
    // because the Angular team has chosen to prefix each one with a dollar sign.
    // So, we just avoid those properties that begin with a dollar sign.
    let controlNames = Object.keys(form).filter(key => key.indexOf('$') !== 0);

    // Set each control back to undefined. This is the only way to clear validation messages.
    // Calling `form.$setPristine()` won't do it (even though you wish it would).
    for (let name of controlNames) {
        let control = form[name];
        control.$setViewValue(undefined);
    }

    form.$setPristine();
    form.$setUntouched();
};
21
battmanz
      $scope.search = {areaCode: xxxx, phoneNumber: yyyy}

フォーム内のすべてのモデルを上記のように1か所に構造化して、次のようにクリアできるようにします。

      $scope.search = angular.copy({});

その後、検証をリセットするためにこれを呼び出すことができます:

      $scope.search_form.$setPristine();
      $scope.search_form.$setUntouched();
      $scope.search_form.$rollbackViewValue();
7
Antoni Xu

角度の$ errorsをリセットする簡単な方法はないようです。おそらく最良の方法は、現在のページをリロードして新しいフォームで開始することです。または、このスクリプトを使用してすべての$ errorを手動で削除する必要があります。

form.$setPristine(true);
form.$setUntouched(true);

// iterate over all from properties
angular.forEach(form, function(ctrl, name) {
  // ignore angular fields and functions
  if (name.indexOf('$') != 0) {
    // iterate over all $errors for each field        
    angular.forEach(ctrl.$error, function(value, name) {
      // reset validity
      ctrl.$setValidity(name, null);
    });
  }
});
$scope.resetCount++; 
5
Michael

検証フラグを追加し、その値に応じてエラーを表示または非表示にすることができますng-ifまたはng-showをHTMLで。フォームには、コントローラーに送信できる$ validフラグがあります。

ng-ifはDOMの要素を削除または再作成しますが、ng-showは追加しますが、表示しません(フラグの値によって異なります)。

[〜#〜] edit [〜#〜]:マイケルが指摘したように、フォームが無効になっていると、私が指摘した方法は機能しません。フォームは送信されません。それに応じてコードを更新しました。

[〜#〜] html [〜#〜]

<form name="searchForm" id="searchForm" ui-event="{reset: 'reset(searchForm)'}" ng-submit="search()">
  <div>
    <label>
      Area Code
      <input type="tel" name="areaCode" ng-model="areaCode" ng-pattern="/^([0-9]{3})?$/">
    </label>

    <div ng-messages="searchForm.areaCode.$error">
      <div class="error" ng-message="pattern" ng-if="searchForm.areaCode.$dirty">The area code must be three digits</div>
    </div>
  </div>

  <div>
    <label>
      Phone Number
      <input type="tel" name="phoneNumber" ng-model="phoneNumber" ng-pattern="/^([0-9]{7})?$/">
    </label>

    <div ng-messages="searchForm.phoneNumber.$error">
      <div class="error" ng-message="pattern" ng-if="searchForm.phoneNumber.$dirty">The phone number must be seven digits</div>
    </div>
  </div>

  <br>
  <div>
    <button type="reset">Reset</button>
    <button type="submit" ng-disabled="searchForm.$invalid">Search</button>
  </div>
</form>

[〜#〜] js [〜#〜]

$scope.search = function() {
    alert('Searching');
};

$scope.reset = function(form) {
     form.$setPristine();
     form.$setUntouched();
     $scope.resetCount++;
 };

動作するソリューションを備えたCodepen: http://codepen.io/anon/pen/zGPZoB

5
Ariel

次は私のために働いた

let form = this.$scope.myForm;   
let controlNames = Object.keys(form).filter(key => key.indexOf('$') !== 0);
for (let name of controlNames) {
    let control = form [name];
    control.$error = {};
}

要するに: ng-messagesエラーを取り除くために$ errorをクリアする必要があります=各フォーム項目のオブジェクト。

2
Sumeet

resetで正しい動作をするようになったようです。残念ながら、標準resetの使用は失敗しました。ライブラリui-eventも含めません。したがって、私のコードはあなたのコードとは少し異なりますが、あなたが必要とするものを実行します。

<form name="searchForm" id="searchForm" ng-submit="search()">
  pristine = {{searchForm.$pristine}} valid ={{searchForm.$valid}}
  <div>
    <label>
      Area Code
      <input type="tel" required name="areaCode" ng-model="obj.areaCode" ng-pattern="/^([0-9]{3})?$/" ng-model-options="{ allowInvalid: true }">
    </label>

    <div ng-messages="searchForm.areaCode.$error">
      <div class="error" ng-message="pattern">The area code must be three digits</div>
      <div class="error" ng-message="required">The area code is required</div>
    </div>
  </div>

  <div>
    <label>
      Phone Number
      <input type="tel" required name="phoneNumber" ng-model="obj.phoneNumber" ng-pattern="/^([0-9]{7})?$/" ng-model-options="{ allowInvalid: true }">
    </label>

    <div ng-messages="searchForm.phoneNumber.$error">
      <div class="error" ng-message="pattern">The phone number must be seven digits</div>
      <div class="error" ng-message="required">The phone number is required</div>
    </div>
  </div>

  <br>
  <div>
    <button ng-click="reset(searchForm)" type="reset">Reset</button>
    <button type="submit" ng-disabled="searchForm.$invalid">Search</button>
  </div>
</form>

そしてJS:

$scope.resetCount = 0;
$scope.obj = {};
$scope.reset = function(form_) {
  $scope.resetCount++;
  $scope.obj = {};
  form_.$setPristine();
  form_.$setUntouched();
  console.log($scope.resetCount);
};

$scope.search = function() {
  alert('Searching');
};

jsfiddle のライブ例。

ディレクティブng-model-options="{allowinvalid: true}"に注意してください。必ず使用するか、入力フィールドが無効になるまで、model値は記録されません。したがって、リセットは動作しません。

追伸オブジェクトに値(areaCode、phoneNumber)を設定すると、精製が簡単になります。

2

私は同じ問題を抱えていたので、battmanzソリューションを実行しようとしました(受け入れられた答え)。

彼の答えは本当に良いと確信していますが、私にとってはうまくいきませんでした。

ng-modelを使用してデータをバインドし、angular入力用のマテリアルライブラリとエラーメッセージ用のng-messageディレクティブを使用しているので、多分私は言うでしょう同じ構成を使用している人にのみ役立ちます。

私はjavascriptのformControllerオブジェクトをよく見てみましたが、実際には多くの$ angular関数がbattmanzが指摘したようにあり、さらに、フィールド名はオブジェクトであり、その分野のいくつかの機能。

では、フォームをクリアするのは何ですか?

通常、フォームはjsonオブジェクトとして表示され、すべてのフィールドはこのjsonオブジェクトのキーにバインドされます。

//lets call here this json vm.form
vm.form = {};

//you should have something as ng-model = "vm.form.name" in your view

したがって、最初はフォームをクリアするために、フォームを送信するコールバックを行いました:

vm.form = {};

そして、この質問で説明したように、ng-messagesはそれで消えません、それは本当に悪いです。

彼が書いたとおりにbattmanzソリューションを使用した場合、メッセージは表示されなくなりましたが、送信した後でも、フィールドを空にしたことはありません。

vm.form = {};

彼のソリューションを使用すると、すべてのフィールドが未定義に設定されるため、フォームからモデルバインディングが実際に削除されるため、正常であることがわかりました。そのため、テキストはまだビュー内にありました。どういうわけか、もはやバインディングがなくなり、HTMLにとどまることにしたからです。

だから私は何をしましたか?

実際には、フィールドをクリアして(バインディングを{}に設定)、使用しただけです

form.$setPristine();
form.$setUntouched();

実際には、バインディングはまだここにあるため、フォームの値は空になり、angular ng-messagesディレクティブはフォームが変更されていない場合にのみトリガーされるため、論理的と思われます。結局のところ。

最終的な(非常に単純な)コードは次のとおりです。

function reset(form) {
        form.$setPristine();
        form.$setUntouched();
};

それで遭遇した大きな問題:

onceのみ、コールバックはどこかでめちゃくちゃになっているようで、フィールドは何とか空ではありませんでした(送信ボタンをクリックしなかったようです)。

もう一度クリックすると、送信された日付が空でした。必要なフィールドが適切なパターンで満たされていない場合、送信ボタンは無効になっているはずなので、それはさらに奇妙です。

私のやり方が最善か、それとも正しいか、わからないことがあります。批評家/提案がある場合、または私が遭遇した問題について何かがあれば、教えてください、私は常にangularJSにステップアップするのが大好きです。

これが誰かを助け、悪い英語をすみません。

1
Alburkerk

@battmanzの答えをさらに詳しく説明しますが、ES6構文を使用せずに古いブラウザーをサポートします。

 $scope.resetForm = function (form) {

            try {
                var controlNames = Object.keys(form).filter(function (key) { return key.indexOf('$') !== 0 });

                console.log(controlNames);
                for (var x = 0; x < controlNames.length; x++) {
                    form[controlNames[x]].$setViewValue(undefined);
                }

                form.$setPristine();
                form.$setUntouched();
            } catch (e) {                
                console.log('Error in Reset');
                console.log(e);
            }

        };
1

LoginFormオブジェクトを関数ng-click="userCtrl.login(loginForm)および関数呼び出しに渡すことができます

this.login = function (loginForm){
  loginForm.$setPristine();
  loginForm.$setUntouched();
}
0
code4j

そのため、私にとって完全に機能する答えはありませんでした。特に、ビューの値をクリアするため、すべての回答を組み合わせてビューの値をクリアし、エラーをクリアし、jクエリで選択をクリアします(フィールドが入力され、モデル名と同じ名前である場合)

 var modelNames = Object.keys($scope.form).filter(key => key.indexOf('$') !== 0);
                    modelNames.forEach(function(name){
                        var model = $scope.form[name];
                        model.$setViewValue(undefined);
                        jq('input[name='+name+']').val('');
                        angular.forEach(model.$error, function(value, name) {
                          // reset validity
                          model.$setValidity(name, null);
                        });
                    });
                    $scope.form.$setPristine();
                    $scope.form.$setUntouched();
0
Diwas Subedi