触发 Angular 表单提交中所有字段的验证

Posted

技术标签:

【中文标题】触发 Angular 表单提交中所有字段的验证【英文标题】:Trigger validation of all fields in Angular Form submit 【发布时间】:2013-06-01 03:45:11 【问题描述】:

我正在使用这种方法:http://plnkr.co/edit/A6gvyoXbBd2kfToPmiiA?p=preview 仅验证模糊字段。这很好用,但是当用户单击“提交”按钮(不是真正的提交,而是对函数的 data-ng-click 调用)时,我还想验证它们(并因此显示这些字段的错误(如果有))

点击该按钮时,是否有某种方法可以再次触发所有字段的验证?

【问题讨论】:

plunkr 中的按钮在哪里? 抱歉,plunker 是我的代码的基础。我做了一个分叉来更接近我的情况:plnkr.co/edit/VfvCSmjlzpIgUH4go2Jn?p=preview 【参考方案1】:

对我有用的是使用 $setSubmitted 函数,它首先出现在 1.3.20 版本的 angular 文档中。

在我想要触发验证的点击事件中,我执行了以下操作:

vm.triggerSubmit = function() 
    vm.homeForm.$setSubmitted();
    ...

这就是我所需要的。根据文档,它“将表单设置为其提交状态”。提到了here。

【讨论】:

这在您使用 ng-messages 时不起作用,并且仅在 $error && $dirty 时显示它们。 @JobaDiniz 你试过 $setDirty 函数吗?我的回答的链接中也提到了这一点:code.angularjs.org/1.3.20/docs/api/ng/type/form.FormController希望有帮助! 它不适用于form...我必须遍历所有输入并在它们上调用$setDirty()【参考方案2】:

我知道,现在回答有点晚了,但您需要做的就是强制所有表格变脏。看看下面的sn-p:

angular.forEach($scope.myForm.$error.required, function(field) 
    field.$setDirty();
);

然后您可以使用以下方法检查您的表单是否有效:

if($scope.myForm.$valid) 
    //Do something
   

最后,我猜,如果一切看起来都不错,你会想改变你的路线:

$location.path('/somePath');

编辑:表单不会在范围内注册,直到提交事件被触发。只需使用 ng-submit 指令调用一个函数,并将上面的内容包装在该函数中,它应该可以工作。

【讨论】:

您能否提供以编程方式触发ng-submit 指令的示例? @chovy ng-submit 只是将一个函数绑定到提交事件,为什么不直接调用该函数呢? 我在表单中嵌入了一个指令,该指令更新了指令之外的表单字段......除非我单击并模糊我想要验证的表单字段,否则不会应用验证器。 我不会有传递给它的表单对象 @chovy 我没有正确理解你。但让我试着帮助你。您是否尝试过去抖动验证?【参考方案3】:

万一以后有人回来...以上都不适合我。因此,我深入研究了 Angular 表单验证的内容,并找到了他们调用的函数来在给定字段上执行验证器。该属性方便地称为$validate

如果您有一个命名表单myForm,您可以通过编程方式调用myForm.my_field.$validate() 来执行字段验证。例如:

<div ng-form name="myForm">
    <input required name="my_field" type="text" ng-blur="myForm.my_field.$validate()">
</div>

请注意,调用 $validate 会对您的模型产生影响。来自 ngModelCtrl.$validate 的角度文档:

运行每个已注册的验证器(首先是同步验证器,然后是异步验证器)。如果有效性更改为无效,则模型将设置为未定义,除非 ngModelOptions.allowInvalid 为 true。如果有效性更改为有效,它会将模型设置为最后一个可用的有效 $modelValue,即最后一个解析值或从范围中设置的最后一个值。

因此,如果您打算使用无效的模型值执行某些操作(例如弹出一条消息告诉他们),那么您需要确保您的模型将 allowInvalid 设置为 true

【讨论】:

更多关于在没有allowInvalid 的情况下非常令人惊讶的“模型变得未定义”结果的讨论可以在这里阅读:github.com/angular/angular.js/issues/10035【参考方案4】:

你可以使用 Angular-Validator 来做你想做的事。使用起来很简单。

它将:

仅验证 $dirtysubmit 上的字段 表单无效时阻止提交 字段为$dirty或提交表单后显示自定义错误消息

See the demo

示例

<form angular-validator 
       angular-validator-submit="myFunction(myBeautifulForm)"
       name="myBeautifulForm">
       <!-- form fields here -->
    <button type="submit">Submit</button>
</form>

如果该字段未通过validator,则用户将无法提交表单。

查看angular-validator use cases and examples了解更多信息。

免责声明:我是 Angular-Validator 的作者

【讨论】:

【参考方案5】:

嗯,有角度的方法是让它处理验证,因为它在每次模型更改时都会进行 - 并且只在需要时向用户显示结果。

在这种情况下,您决定何时显示错误,您只需设置一个标志: http://plnkr.co/edit/0NNCpQKhbLTYMZaxMQ9l?p=preview

据我所知,有一个问题提交给 Angular,让我们拥有更高级的表单控制。由于它没有解决,我会使用它而不是重新发明所有现有的验证方法。

编辑:但是如果您坚持自己的方式,这是您在提交前进行验证的修改后的小提琴。 http://plnkr.co/edit/Xfr7X6JXPhY9lFL3hnOw?p=preview 当按钮被点击时,控制器会广播一个事件,并且指令会执行验证魔法。

【讨论】:

这在这个例子中有效,但是如果我,就像我在我的情况下(但不是在那个 plunkr..sorry!),还有一个像那个电子邮件一样的指令。我是否必须以某种方式将验证从指令移到单独的验证类中,然后调用此表单的所有验证方法,或者我可以以某种方式以另一种方式触发所有指令的验证。由于验证是由模糊触发的,甚至可能会从代码中触发模糊,但这看起来很可怕。 哦,我知道这个问题。不幸的是,它甚至还没有处于测试阶段,我正在谈论的工作流程是这家公司所必需的 广播的事件将触发每个指令中的 $on 回调,因为它们都在控制器的范围内。 啊..并没有真正理解那部分。谢谢! 广播事件时可以传递参数。 $scope.$broadcast('startValidations', param1, param2);监听保持不变:scope.$on('startValidations', validateMe);并在回调 fn: function validateMe( event, param1, param2 ) 查看文档:docs.angularjs.org/api/ng.$rootScope.Scope#$broadcast【参考方案6】:

一种方法是强制所有属性变脏。您可以在每个控制器中执行此操作,但它会变得非常混乱。最好有一个通用的解决方案。

我能想到的最简单的方法是使用指令

它将处理表单提交属性 它遍历所有表单字段并将原始字段标记为脏 在调用提交函数之前检查表单是否有效

这是指令

myModule.directive('submit', function() 
  return 
    restrict: 'A',
    link: function(scope, formElement, attrs) 
      var form;
      form = scope[attrs.name];
      return formElement.bind('submit', function() 
        angular.forEach(form, function(field, name) 
          if (typeof name === 'string' && !name.match('^[\$]')) 
            if (field.$pristine) 
              return field.$setViewValue(field.$value);
            
          
        );
        if (form.$valid) 
          return scope.$apply(attrs.submit);
        
      );
    
  ;
);

并更新你的表单html,例如:

 <form ng-submit='justDoIt()'>

变成:

 <form name='myForm' novalidate submit='justDoIt()'>

在此处查看完整示例:http://plunker.co/edit/QVbisEK2WEbORTAWL7Gu?p=preview

【讨论】:

【参考方案7】:

这是显示表单错误消息的全局函数。

 function show_validation_erros(form_error_object) 
        angular.forEach(form_error_object, function (objArrayFields, errorName) 
            angular.forEach(objArrayFields, function (objArrayField, key) 
                objArrayField.$setDirty();
            );
        );
    ;

在我的任何控制器中,

if ($scope.form_add_sale.$invalid)  
    $scope.global.show_validation_erros($scope.form_add_sale.$error);

【讨论】:

这不能回答问题。 我改变了答案。请立即查看【参考方案8】:

根据 Thilak 的回答,我能够想出这个解决方案...

由于我的表单字段仅在字段无效并且已被用户触摸时才显示验证消息,因此我能够使用由按钮触发的此代码来显示我的无效字段:

// Show/trigger any validation errors for this step
angular.forEach(vm.rfiForm.stepTwo.$error, function(error) 
  angular.forEach(error, function(field) 
    field.$setTouched();
  );
);
// Prevent user from going to next step if current step is invalid
if (!vm.rfiForm.stepTwo.$valid) 
  isValid = false;
<!-- form field -->
<div class="form-group" ng-class=" 'has-error': rfi.rfiForm.stepTwo.Parent_Suffix__c.$touched && rfi.rfiForm.stepTwo.Parent_Suffix__c.$invalid ">

  <!-- field label -->
  <label class="control-label">Suffix</label>
  <!-- end field label -->
  <!-- field input -->
  <select name="Parent_Suffix__c" class="form-control"
          ng-options="item.value as item.label for item in rfi.contact.Parent_Suffixes"
          ng-model="rfi.contact.Parent_Suffix__c" />
  <!-- end field input -->
  <!-- field help -->
  <span class="help-block" ng-messages="rfi.rfiForm.stepTwo.Parent_Suffix__c.$error" ng-show="rfi.rfiForm.stepTwo.Parent_Suffix__c.$touched">
    <span ng-message="required">this field is required</span>
  </span>  
  <!-- end field help -->
</div>
<!-- end form field -->

【讨论】:

【参考方案9】:

注意:我知道这是一个 hack,但它对 Angular 1.2 及更早版本很有用,因为它没有提供简单的机制。

验证在 change 事件中启动,因此以编程方式更改值等某些事情不会触发它。但是触发 change 事件会触发验证。例如,使用 jQuery:

$('#formField1, #formField2').trigger('change');

【讨论】:

这种方法很简单。此外,它还具有适用于旧(所有)版本的 Angular 的优势。 不是angular way【参考方案10】:

我喜欢this approach 在处理按钮点击验证方面。

    不需要从控制器调用任何东西,

    都是用指令处理的。

在github

【讨论】:

【参考方案11】:

你可以试试这个:

// The controller

$scope.submitForm = function(form)
   		//Force the field validation
   		angular.forEach(form, function(obj)
   			if(angular.isObject(obj) && angular.isDefined(obj.$setDirty))
   			 
   				obj.$setDirty();
   			
   		)
        
        if (form.$valid)
		
			$scope.myResource.$save(function(data)
		     	//....
			);
		
<!-- FORM -->

  <form name="myForm"  role="form" novalidate="novalidate">
<!-- FORM GROUP to field 1 -->
  <div class="form-group" ng-class=" 'has-error' : myForm.field1.$invalid && myForm.field1.$dirty ">
      <label for="field1">My field 1</label>
        <span class="nullable"> 
        <select name="field1" ng-model="myresource.field1" ng-options="list.id as list.name for list in listofall"
          class="form-control input-sm" required>
            <option value="">Select One</option>
        </select>
        </span>
        <div ng-if="myForm.field1.$dirty" ng-messages="myForm.field1.$error" ng-messages-include="mymessages"></div>
  </div>
    
<!-- FORM GROUP to field 2 -->
  <div class="form-group" ng-class=" 'has-error' : myForm.field2.$invalid && myForm.field2.$dirty ">
    <label class="control-label labelsmall" for="field2">field2</label> 
      <input name="field2" min="1" placeholder="" ng-model="myresource.field2" type="number" 
      class="form-control input-sm" required>
    <div ng-if="myForm.field2.$dirty" ng-messages="myForm.field2.$error" ng-messages-include="mymessages"></div>
  </div>

  </form>

<!-- ... -->
<button type="submit" ng-click="submitForm(myForm)">Send</button>

【讨论】:

【参考方案12】:

我做了以下事情来使它工作。

<form name="form" name="plantRegistrationForm">
  <div ng-class=" 'has-error': (form.$submitted || form.headerName.$touched) && form.headerName.$invalid ">
    <div class="col-md-3">
      <div class="label-color">HEADER NAME 
        <span class="red"><strong>*</strong></span></div>
    </div>
    <div class="col-md-9">
      <input type="text" name="headerName" id="headerName" 
             ng-model="header.headerName" 
             maxlength="100" 
             class="form-control" required>
      <div ng-show="form.$submitted || form.headerName.$touched">
        <span ng-show="form.headerName.$invalid" 
              class="label-color validation-message">Header Name is required</span>
      </div>
    </div>
  </div>

  <button ng-click="addHeader(form, header)" 
          type="button" 
          class="btn btn-default pull-right">Add Header
  </button>

</form>

在你的控制器中你可以做到;

addHeader(form, header)
        let self = this;
        form.$submitted = true;
        ... 
    

你还需要一些 CSS;

.label-color 
            color: $gray-color;
        
.has-error 
       .label-color 
            color: rgb(221, 25, 29);
        
        .select2-choice.ui-select-match.select2-default 
            border-color: #e84e40;
        
    
.validation-message 
       font-size: 0.875em;
    
    .max-width 
        width: 100%;
        min-width: 100%;
    

【讨论】:

【参考方案13】:

为了在需要时验证表单的所有字段,我对 $$controls 的每个字段进行验证,如下所示:

angular.forEach($scope.myform.$$controls, function (field) 
    field.$validate();
);

【讨论】:

以上是关于触发 Angular 表单提交中所有字段的验证的主要内容,如果未能解决你的问题,请参考以下文章

多个字段的Angular 4表单验证

在 Angular 单元测试中使用回车键提交表单

触发动作表单提交JavaScript的HTML

AngularJS:表单内的所有按钮触发提交?

Angular 7 - 使用 FormControl 字段启用提交表单

验证失败时阻止表单提交(Angular Material)