如何重置表单,包括删除所有验证错误?

时间:2015-06-23 17:58:52

标签: html angularjs ng-messages

我有一个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>

正如您所看到的,当表单重置时,它会调用reset上的$scope方法。这是整个控制器的样子:

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 {2}的another question的建议。我添加计数器的唯一原因是证明代码被调用(它是)。

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

Validation Errors

10 个答案:

答案 0 :(得分:21)

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

我注意到Angular form对象具有每个控件(input,select,textarea等)的属性以及一些其他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();
};

答案 1 :(得分:7)

      $scope.search = {areaCode: xxxx, phoneNumber: yyyy}

将表单中的所有模型组织在一个如上所示的位置,以便您可以像这样清除它:

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

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

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

答案 2 :(得分:5)

您可以添加验证标记,并在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

答案 3 :(得分:5)

似乎没有一种简单的方法来重置角度中的$ errors。最好的方法可能是重新加载当前页面以使用新表单开始。或者,您必须使用此脚本手动删除所有$ error:

{{1}}

答案 4 :(得分:2)

看起来我必须在重置做正确的行为。遗憾的是,使用标准重置失败。我也没有包含库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}"。必须使用它,或者在输入字段无效之前,不记录模型值。因此,重置将无法运行。

P.S。将值(areaCode,phoneNumber)放在对象上简化了纯化。

答案 5 :(得分:2)

以下为我工作

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

答案 6 :(得分:1)

进一步回答@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);
            }

        };

答案 7 :(得分:1)

我遇到了同样的问题并试图做battmanz解决方案(接受回答)。

我很确定他的回答非常好,但对我而言却没有用。

我正在使用ng-model来绑定数据,使用角度材料库来输入​​错误消息的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 = {};

我发现它是正常的,因为使用他的解决方案实际上从表单中删除了模型绑定,因为它将所有字段设置为undefined。 所以文本仍然在视图中,因为不知何故不再有任何约束,它决定留在HTML中。

那我做了什么?

实际上我只是清除字段(将绑定设置为{}),并且只使用

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

实际上它似乎是合乎逻辑的,因为绑定仍在这里,表单中的值现在是空的,并且仅当表单没有被触及时才会触发angular ng-messages指令,所以我认为这毕竟是正常的。

最终(非常简单)代码是:

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

我遇到的一个大问题是:

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

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

我不知道我的做事方式是最好的还是正确的,如果你有任何批评/建议或任何我遇到的问题,请告诉我,我总是喜欢加入angularJS。

希望这会有所帮助,对不好的英语感到抱歉。

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

所以没有一个答案完全适合我。 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();