AngularJs 自定义表单验证(依赖验证)

我们在使用Angularjs进行开发时,已经提供了非常完备的表单验证框架,可以帮助我们很好的进行表单的校验工作,可是有时候因为一些业务逻辑的问题,会产生一些特殊的验证问题,这个时候我们就需要在angularjs中使用自定义验证了。

就比如我们这里的一个简单问题:从下面两张图中可以简单看到,在表单中有个邮件服务器配置的选项,如果启用,则必须填写展开的数据项。所以也就是说,关于邮件服务器配置项数据的校验是根据是否启用来做的。
邮件服务器配置默认状态

邮件服务器配置启用状态

实现方案

  1. 如果按照以前的开发方式,这种校验逻辑就是小毛毛雨,因为所有的表单验证都是自己写的,一串if-elseif-else就可以很好的实现出来。这样写没错,还能更好的理解表单验证的逻辑,适合学习的时候这样写,可是在实际项目开发过程中
    这样写就有点反人类了,N多个字段,N多种校验,排查维护起来也是不小的工作。

  2. 使用验证框架,验证框架何其多,使用验证框架可以帮助我们很好的简单快捷完成表单验证,由于主要是介绍angularjs,所以就使用angularjs的验证框架来完成这种验证规则,当邮件服务器配置不启用的时候,则不会去验证邮件的配置项,如果启用了,则需要验证。

后续的内容需要有了解或使用过angularjs表单验证功能的基础,如果不是很了解,建议选查看一下angularjs是如何使用表单验证的,或者可以参考:

分析的过程就不多说了,直接上代码,大家可以在实践的过程中来理解。由于个人知识有限,也许angularjs已经提供过相关的验证方式,只是我没有了解到,如果有朋友知道,还请留言告知,谢过!

html代码段 - 一个简单的表单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<form name="youname_form" novalidate>
<div class="form_item">
<label class="form_label ">其他必填设置:</label>
<div class="form_input">
<input type="text" name="other_val" ng-model="configData.otherVal" required>
</div>
<div class="form_message">
<span class="success" ng-show="youname_form.other_val.$dirty && youname_form.other_val.$valid"><i class="tongtech tbcl-duihao">成功</i></span>
<span class="error" ng-show="youname_form.other_val.$dirty && youname_form.other_val.$error.required">请填写其他设置</span>
</div>
</div>
<div class="form_item">
<label class="form_label ">邮件配置:</label>
<div class="form_input">
<input type="checkbox" ng-model="configData.mailServer.enable">
</div>
<div class="form_message">
<span class="prompt"></span>
</div>
</div>
<div ng-show="configData.mailServer.enable">
<div class="form_item">
<label class="form_label ">STMP服务地址:</label>
<div class="form_input">
<input type="text" name="mailServer_smtp" ng-model="configData.mailServer.smtp" >
</div>
<div class="form_message">
<span class="success" ng-show="youname_form.mailServer_smtp.$dirty && youname_form.mailServer_smtp.$valid"><i class="tongtech tbcl-duihao">成功</i></span>
<span class="error" ng-show="youname_form.mailServer_smtp.$dirty && youname_form.mailServer_smtp.$error.required">请填写STMP服务地址</span>
</div>
</div>
</div>
<div class="form_item">
<button ng-click="saveConfig(youname_form.$valid)">保存配置</button>
<span>表单验证状态:{{youname_form.$valid}}</span>
</div>
</form>
js代码段 - 使用angularjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var testModule = angular.module("tmodule", []);
testModule.controller("testCtrl", function($scope) {
$scope.configData = {
otherVal:'',
mailServer:{
enable: false,
smtp: ''
}
};
var editVali = function(item) {
item.$dirty = true;
item.$pristine = false;
}
$scope.saveConfig = function(state) {
//表单校验
if(!state) {
editVali($scope.youname_form.other_val);
if($scope.configData.mailServer.enable) {
editVali($scope.youname_form.mailServer_smtp);
}
return;
}
alert('验证成功!');
}
});

代码运行效果
从上图不难看出,有个很明显的错误,当邮件配置启用的时候,STMP的验证是通过的。这是因为我们在html代码段第25行并没有添加required(必填)属性,导致该项为非必填项。

如果给添加上required(必填)属性呢?我们可以想一下(也可以自己试一下),如果添加上,那么表示该项为必填项,无论邮件配置是否启用,这里都会进行非空校验,所以也是不可取的。

所以说,单纯的required(必填)校验并不能满足我们的需求,我们需要对required(必填)校验进行扩展,来让这个非空的校验是有条件的判断。

接下来使用angularjs的自定义校验来扩展required(必填),我们命名为required-for,指定一个作为判断条件的属性,根据指定的属性来进行有条件的非空校验。注意:扩展的自定义验证,需要使用高版本的angularjs,只测试了一个1.2.6不支持扩展,1.4.6支持扩展。

js代码段 - 扩展required校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
testModule.directive('requiredFor',function(){
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, ele, attrs, ctrl){
if (!ctrl) return;
var paramVal = null;
scope.$watch(attrs.requiredFor, function(n){
paramVal = n;
ctrl.$validate();
});
ctrl.$validators.required = function(modelValue, viewValue) {
return !paramVal || !ctrl.$isEmpty(viewValue);
};
ctrl.$parsers.push(function(viewValue){
if(paramVal){
if(ctrl.$isEmpty(viewValue)){
ctrl.$setValidity('required', false);
}else{
ctrl.$setValidity('required', true);
}
}else{
ctrl.$setValidity('required', true);
}
return viewValue;
});
}
};
});

然后我们在html代码段第25行添加我们新的校验指令required-for=””

html代码段 - 添加新的校验指令
1
<input type="text" name="mailServer_smtp" ng-model="configData.mailServer.smtp" required-for="configData.mailServer.enable">

代码运行效果
通过上图我们可以看到,表单的验证状态将会根据邮件配置的是否启用和STMP项是否填值来进行变化。

示例代码:https://github.com/yecaocode/angularjs-base/blob/master/L005.html

参考资料

  1. 整理后补