【问题标题】:How do I reset a form including removing all validation errors?如何重置表单,包括删除所有验证错误?
【发布时间】:2015-09-09 16:24:57
【问题描述】:

我有一个 Angular 表单。这些字段使用ng-pattern 属性进行验证。我也有一个重置按钮。我正在使用Ui.Utils Event Binder 来处理reset 事件,如下所示:

<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');
    };
});

我正在调用 form.$setPristine()form.$setUntouched,遵循 Stack Overflow 上 another question 的建议。我添加计数器的唯一原因是为了证明代码正在被调用(确实如此)。

问题是即使在重置表单之后,验证消息也不会消失。您可以在Plunker 上查看完整代码。这是显示错误不会消失的屏幕截图:

【问题讨论】:

  • 唯一对我有用的是手动重置每个表单变量(即form.areaCode = '';form.phoneNumber = '';)。这就是你通常的做法。

标签: html angularjs ng-messages


【解决方案1】:

您可以在 HTML 中使用 ng-ifng-show 添加验证标志并根据其值显示或隐藏错误。该表单有一个 $valid 标志,您可以将其发送到您的控制器。

ng-if 将删除或重新创建元素到 DOM,而ng-show 将添加它但不会显示它(取决于标志值)。

编辑:正如迈克尔所指出的,如果表单被禁用,我指出的方式将不起作用,因为表单从未提交过。相应地更新了代码。

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

【讨论】:

  • 使用此解决方案,您根本不会看到任何错误,因为 Search 按钮已禁用,并且您无法触发 search 函数来显示错误。另一种简单的方法是检查输入字段是否脏:ng-if="searchForm.phoneNumber.$dirty"
  • 错过了 ng-disabled,我的错,我会根据你的建议更新代码 Michael。感谢您指出这一点。
  • 我不想只隐藏验证消息,因为正如@Michael 指出的那样,只要表单无效,我就会禁用提交按钮。我需要表单在重置后实际上是有效的(不仅仅是看起来有效)。
【解决方案2】:

我从@Brett 的评论开始,并以此为基础。我实际上有多个表单,每个表单都有很多字段(不仅仅是显示的两个)。所以我想要一个通用的解决方案。

我注意到 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();
};

【讨论】:

  • 请注意,这种方法可以有效地总结如下:“form.$setPristine() 不会清除错误。您必须将所有表单控件显式设置回undefined。”
  • undefined 成功了!但是,仅通过访问表单数据来使该字段稍后再次重新验证自己似乎是不可能的。不知道我是否错过了……:(我试过form.Field.$setDirty(true); form.Field.$validate(); form.$setSubmitted();但没有用。
【解决方案3】:

似乎没有一种简单的方法可以重置角度中的 $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++; 

【讨论】:

    【解决方案4】:

    您可以将您的 loginForm 对象传递给函数ng-click="userCtrl.login(loginForm) 并在函数调用中

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

    【讨论】:

      【解决方案5】:

      看来我必须在重置时做出正确的行为。不幸的是,使用标准 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)放在对象上可以简化净化。

      【讨论】:

      • 答案很完美,只是我想补充一点。如果您在重置函数中调用form_.$setPristine();form_.$setUntouched();,则ng-invalid 类将消失,因此表单字段不会被标记为红色
      • 这对我有用 ng-model-options="{ allowInvalid: true }" 这很有帮助。在这方面苦苦挣扎了一段时间。
      【解决方案6】:
            $scope.search = {areaCode: xxxx, phoneNumber: yyyy}
      

      像上面一样将表单中的所有模型构建在一个地方,这样你就可以像这样清除它:

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

      之后你可以调用它来重置验证:

            $scope.search_form.$setPristine();
            $scope.search_form.$setUntouched();
            $scope.search_form.$rollbackViewValue();
      

      【讨论】:

        【解决方案7】:

        进一步了解@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);
                    }
        
                };
        

        【讨论】:

          【解决方案8】:

          以下对我有用

          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 对象。

          【讨论】:

            【解决方案9】:

            我有同样的问题,并尝试做 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();
            };
            

            我遇到的一个大问题:

            只有一次,回调似乎在某个地方搞砸了,而且字段不为空(就像我没有点击提交按钮一样)。

            当我再次点击时,发送的日期是空的。这更奇怪,因为当必填字段没有用好的模式填充时,我的提交按钮应该被禁用,而空的肯定不是一个好的模式。

            我不知道我的做法是最好的还是正确的,如果您对我遇到的问题有任何批评/建议或任何想法,请告诉我,我总是喜欢在 angularJS 中加紧。

            希望这会对某人有所帮助,并对糟糕的英语感到抱歉。

            【讨论】:

              【解决方案10】:

              所以没有一个答案完全适合我。 ESP,清除视图值,所以我将所有答案合并为清除视图值,清除错误和清除选择与 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();
              

              【讨论】:

                猜你喜欢
                • 2014-05-30
                • 1970-01-01
                • 2012-08-30
                • 2019-03-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-11-14
                相关资源
                最近更新 更多