13 表单验证

表单验证

内置表单验证指令

Angular提供了一些常用的html5输入控件的验证实现:(text, number, url, email, radio, checkbox), 以及一些用于验证的指令 (required, pattern, minlength, maxlength, min, max)。这里只介绍模式匹配ng-pattern指令。

使用ng-pattern="/PATTERN/"来确保输入能够匹配指定的正则表达式:

注意:要使用HTML 表单属性 novalidate 禁用浏览器默认的验证。

表单属性

属性 描述 对应的CSS样式
$dirty 表单有填写记录 .ng-dirty {}
$valid 字段内容合法的 .ng-valid {}
$invalid 字段内容是非法的 .ng-invalid {}
$pristine 表单没有填写记录 .ng-pristine {}
$error 当前表单的所有验证内容,以及它们是否合法的信息。如果验证失败,这个属性的值为true;如果值为false,说明输入字段的值通过了验证。

你可以使用formName.inputFieldName.property来验证某个输入框的内容,或通过formName.property来验证整个表单所有输入框的内容。

ngModel.NgModelController

一个表单是一个 FormController 的实例。

一个拥有 api/ng.directive:ngModel 指令的输入控件,包含一个NgModelController实例。

ngModel.NgModelController为ng-model指令提供了API。该控制器包含数据绑定,验证,CSS更新服务,和值的格式化和解析。它很明确的不包含任何逻辑处理,DOM渲染或者监听事件。这种与DOM相关的逻辑应该由其他使用NgModelController进行数据绑定指令提供。

方法

$render();

当视图需要更新时调用。

$isEmpty(value);

当我们需要判断input的值是否为空时可执行。例如, input的值是否存在,则需要的指令执行此函数。默认的$isEmpty函数检查值是否是“undefined”、“”、null或者NaN。

Value:检查的引用。

$setValidity(validationErrorKey,isValid);

改变有效性的状态,并通知表单当前控制器的有效性发生变化。(如果验证器已经被标记为无效,则不通知表单。)

在需要验证的时候这种方法被调用—即分析器或格式化功能。

validationErrorKey:验证器的名称。validationErrorKey将会被分配给$error[validationErrorKey ] =isValid,这样就可以进行数据绑定了。

isValid:当前状态是否是valid(true)或者invalid(false)。

$setPristine();

设置控制器初始化状态。

$setViewValue(value);

更新页面的值。

当页面上的值发生变化时,这个方法被调用。

value:页面上的值。

属性

$viewValue

页面上实际的字符串值。

$modelValue

模型中控制器绑定的的该值。$modelValue由数据模型持有。$modelValue$viewValue可能是不同的,取决于$parser流水线是否对其进行了操作。

$parsers

被执行的功能数组,作为一个控制器从DOM读取值的管道。每一个函数被调用去传递值到下一个,最后返回值用于填充模型。用于净化/转换或者验证值。为了验证,解析器应该使用$setvalidity()更新有效状态,并返回未定义的无效值。

$formatters

被执行功能的数组,作为一个控制器从DOM读取值的管道。每一个函数被调用去传递值到下一个,最后返回值用于填充模型。用于的格式化/转换在控制器和验证中显示的值。

$viewChangeListeners

当页面上值变化时所执行的函数的数组。它没有参数被执行,它的返回值被忽略。这可以用来代替对模型值额外的监听。

$error

带有所有错误的hash对象。

$pristine

用户还没有与控制器交互,则为true。

$dirty

用户已经与控制器交互,则为true。

$valid

如果没错误,则为true。

$invalid

控制器上至少有一个错误,则为true。

自定义验证

表单的验证在两个时机触发:

  • 数据到视图的更新 - 任何时候,受约束的模型改变时,所有在NgModelController#$formatters数组中的方法会被管道式调用(即:一个接一个的调用方法),这样一来,所有的方法都有机会对值来进行格式化并改变表单和控件的有效性状态,这将通过调用NgModelController#$setValidity来实现。
  • 视图到数据的更新 - 类似的,当用户与一个控件交互时,调用NgModelController#$setViewValue. 这又反过来管式调用了所有在NgModelController#$parsers数组中的方法,这样一来,所有的方法都有机会对值来进行转换并改变表单和控件的有效性状态,通过NgModelController#$setValidity来实现。

$parsers

使用$parsers数组是实现自定义验证的途径之一。例如,假设我们想要确保输入值在某两个数值之间,可以在$parsers数组中入栈一个新的函数,这个函数会在验证链中被调用。

每个$parser返回的值都会被传入下一个$parser中。当不希望数据模型发生更新时返回undefined。

angular.module('myApp')
.directive('oneToTen', function() {
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
ngModel.$parsers.unshift(function(viewValue) {
var i = parseInt(viewValue);
if (i >= 0 && i < 10) {
ngModel.$setValidity('oneToTen', true);
return viewValue;
} else {
ngModel.$setValidity('oneToTen', false);
return undefined;
}
});
}
};
});

$formatters

当绑定的ngModel值发生了变化,并经过$parsers数组中解析器的处理后,这个值会被传递给$formatters流水线。同$parsers数组可以修改表单的合法性状态类似,$formatters中的函数也可以修改并格式化这些值。

比起单纯的验证目的,这些函数更常用来处理视图中的可视变化。例如,假设我们要对某个值进行格式化。通过$formatters数组可以在这个值上执行过滤器:

angular.module('myApp')
.directive('oneToTen', ['$filter', function($filter) {
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
ngModel.$formatters.unshift(function(v) {
return $filter('number')(v);
});
}
};
}]);

自定义form控件(使用 ‘ngModel’)

为了能让自定义控件能够与’ngModel’正常工作,达到双向绑定的效果,它需要:

  • 实现 $render方法,它负责在数据传递给方法NgModelController#$formatters之后渲染数据。
  • 调用 $setViewValue 方法,在任何用户与控件交互后,模型需要更新的时候调用。这通常在一个DOM事件监听器里完成。

ngModel.$setViewValue(value)函数会更新控制器上本地的$viewValue,然后将值传递给每一个$parser函数(包括验证器)。

当值被解析,且$parser流水线中所有的函数都调用完成后,值会被赋给$modelValue属性,并且传递给指令中ng-model属性提供的表达式。

最后,所有步骤都完成后,$viewChangeListeners中所有的监听器都会被调用。

注意,单独调用$setViewValue()不会唤起一个新的digest循环,因此如果想更新指令,需要在设置$viewValue后手动触发digest。

$setViewValue()方法适合于在自定义指令中监听自定义事件(比如使用具有回调函数的jQuery插件),我们会希望在回调时设置$viewValue并执行digest循环。

angular.module('form-example2', []).directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
// 视图 -> 模型
elm.on('blur', function() {
scope.$apply(function() {
ctrl.$setViewValue(elm.html());
});
});

// 模型 -> 视图
ctrl.$render = function() {
elm.html(ctrl.$viewValue);
};

// 从DOM中初始化数据
ctrl.$setViewValue(elm.html());
}
};
});

注意,这个指令没有隔离作用域。如果给这个指令设置隔离作用域,将导致内部ngModel无法更新外部ngModel的对应值:AngularJS会在本地作用域以外查询值。

ngMessages

在验证表单填入数据时,如果数据有错或无效会显示提示信息,在用angular写表单时,提示信息可以用ng-show在触发情况是显示,为了减少重复标记,可以利用ngMessages指令。

angular-messages是angular的一个模块,可以作为应用程序依赖模块引入:

angular.module("MyApp",["ngMessages"]);
<form name="signup_form" novalidate ng-submit="signupForm()" ng-controller="signupController">
<label>Your namelabel>
<input type="text"
placeholder="Name"
name="name"
ng-model="signup.name"
ng-minlength=3
ng-maxlength=20 required/>
<div class="error" ng-messages="signup_form.name.$error">
<div ng-message="required">Make sure you enter your namediv>
<div ng-message="minlength">Your name must be least 3 charactersdiv>
<div ng-message="maxlength">Your name cannot be longer than 20 charactersdiv>
div>
<button type="submit">Submitbutton>
form>

这样如果填入表单数据有误,就会出现提示,一次只会出现一个消息,而且出现的顺序就是代码中的顺序,如果需要同时显示所有错误,就需要在ng-messages指令旁加上ng-messages-mutiple

或者很多时候视图中多个地方需要调用相同的提示消息,这时可以将消息保存到模板中,如下:

方法1

<!--In template/error.html-->
<div ng-message="required">This field is requireddiv>
<div ng-message="minlength">The field must be at least 3 charactersdiv>
<div ng-message="maxlength">The field cannot be longer than 20 charactersdiv>

方法2


<script type="text/ng-template" id="my-custom-messages">
"required">This field is required</div>
This field is too shortdiv> script>

然后在视图中使用ng-messages-include引入此模板地址或id:

<div class="error" ng-messages="signup_form.name.$error" ng-messages-include="template/error.html">

div>
<div class="error" ng-messages="signup_form.name.$error" ng-messages-include="my-custom-messages">

div>

你可能感兴趣的:(angularjs)