由浅入深剖析Angular表单验证

前端之家收集整理的这篇文章主要介绍了由浅入深剖析Angular表单验证前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

最近手上维护的组件剩下的BUG都是表单验证,而且公司的表单验证那块代码经历的几代人,里面的逻辑开始变得不清晰,而且代码结构不是很angular。

是很有必要深入了解表单验证。

ngModel是angular的黑魔法,实现双向绑定,当name的值变化的时候,input的value也会跟着变化。

用户在input修改value的时候,name的值也会跟着变化。

novalidate="novalidate"的目的是去除系统自带的表单验证。

上面那段代码解析完,angular会在MainController的$scope下面生成一个变量"form",$scope.form,这个变量的名称跟html中form.name一致。

而$scope.form.text为文本输入框的Model,继承自ngModelController。

其中$scope.form实例自FormController。其内容为:

文本输入框的Model(也就是$scope.form.text)为:

其中$dirty/$pristine,$valid/$invalid,$error为常用属性。尤其是$error。

最简单的表单验证:

了解了form和输入框,就可以先撸个最简单的显示错误的指令。

html内容如下:

指令代码如下:

显示错误 directive("errorTip",function($compile){ return { restrict:"A",require:"ngModel",link:function($scope,$element,$attrs,$ngModel){ //创建子scope var subScope = $scope.$new(),//错误标签的字符串,有错误的时候,显示错误内容 tip = ''; //脏,而且无效,当然属于错误了 $scope.hasError = function(){ return $ngModel.$invalid && $ngModel.$dirty; } //放回ngModel的错误内容,其实就是一个对象{email:true,xxx:true,xxxx:trie} $scope.errors = function(){ return $ngModel.$error; } //编译错误的指令,放到输入框后面 $element.after($compile(tip)(subScope)); } } });

先看看执行结果:

输入无效的邮箱地址的时候:

输入正确的邮箱地址的时候:

errorTip指令一开始通过 require:"ngModel" 获取ngModelController。然后创建用于显示错误的元素到输入框。

这里使用了$compile,$compile用于动态编译显示html内容的。

当有错误内容的时候,错误的元素就会显示

为什么subScope可以访问hasError和errors方法

因为原型链。看下图就知道了。

自定义错误内容

好了,很明显现在的表单验证是不能投入使用的,我们必须自定义显示错误内容,而且要显示错误不仅仅只有一个。

显示多个错误使用ng-repeat即可,也就是把"errorTip"指令中的

改成:

' + '';

其中errorFilter是一个过滤器,用于自定义显示错误信息的。过滤器其实是个函数

代码如下:

结果如下:

好了,到这里就能够处理“简单”的表单验证了。对,简单的。我们还必须继续深入。

自定义表单验证!

那我们就来实现一个不能输入“帅哥”的表单验证吧。

指令如下:

结果如下:

这里有两个关键的东西,$ngModel.$parsers和$ngModel.$setValidity.

$ngModel.$parsers是一个数组,当在输入框输入内容的时候,都会遍历并执行$parsers里面的函数

$ngModel.$setValidity("handsome",false);设置handsome为无效,会设置$ngModel.$error["handsome"] = true;

也会设置delete $ngModel.$$success["handsome"],具体可以翻翻源码。

-->用户输入

-->angular执行所有$parsers中的函数

-->遇到$setValidity("xxoo",false);那么就会把xxoo当做一个key设置到$ngModel.$error["xxoo"]

-->然后errorTip指令会ng-repeat $ngModel.$error

-->errorFilter会对错误信息转义

-->最后显示错误的信息

自定义输入框的显示内容

很多时候开发,不是简简单单验证错误显示错误那么简单。有些时候我们要格式化输入框的内容

例如,"1000"显示成"1,000"

"hello"显示成"Hello"

现在让我们实现自动首字母大写。

源码如下:

.directive("upperCase",function(){ return { restrict:"A",$ngModel){ $ngModel.$parsers.push(function(value){ var viewValue; if(angular.isUndefined(value)){ viewValue = ""; }else{ viewValue = "" + value; } viewValue = viewValue[0].toUpperCase() + viewValue.substring(1); //设置界面内容 $ngModel.$setViewValue(viewValue); //渲染到界面上,这个函数很重要 $ngModel.$render(); return value; }) } } });

这里我们使用了$setViewValue和$render,$setViewValue设置viewValue为指定的值,$render把viewValue显示到界面上。

很多人以为使用了$setViewValue就能更新界面了,没有使用$render,最后不管怎么搞,界面都没刷新。

如果只使用了$ngModel.$parsers是不够的,$parsers只在用户在输入框输入新内容的时候触发,还有一种情况是需要重新刷新输入框的内容的:

那就是双向绑定,例如刚才的输入框绑定的是MainController中的$scope.name,当用户通过其他方式把$scope.name改成"hello",输入框中看不到首字母大写。

这时候就要使用$formatters,还是先看个例子吧.

随机

MainController的内容:

够简单吧,点击按钮的时候,$scope.name变成hello开头的随机内容.

很明显,hello的首字母没大写,不是我们想要的内容

我们修改下指令的内容:

0 ? value[0].toUpperCase() + value.substring(1) : ""; } } } });

总结一下:

1. -->用户在输入框输入内容

-->angular遍历$ngModel.$parsers里面的函数转换输入的内容,然后设置到$ngModel.$modelValue

-->在$ngModel.$parsers数组中的函数里,我们修改了$ngModel.$viewValue,然后$ngMode.$render()渲染内容

2.

-->通过按钮生成随机的字符串设置到name

-->每次脏检测都会判断name的值是否跟$ngModel.$modelValue不一致(这里是使用$watch实现的),不一致就反序遍历$formaters里面的所有函数并执行,把最终返回值赋值到$ngModel.$viewValue

-->刷新输入框内容

自定义输入框的显示内容”的例子能不能优化?

为什么要优化?

原因很简单,为了实现“自定义内容”,使用了$parsers和$formatters,其实两者的内容很像!这一点很关键。

怎么优化?

使用$ngModel.$validators。

好,现在把例子再改一下。

0 ? value[0].toUpperCase() + value.substring(1) : ""; } } } })

代码简洁了很多,$ngModel.$validators在1.3以上的版本才支持

$ngModel.$validators.uppercase函数的返回值如果是false,那么$ngModel.$error['uppercase']=true。这一点跟$ngModel.$setValidity("uppercase",false)差不多。

猜你在找的JavaScript相关文章