从浅入深剖析angular表单验证(ant 表单验证)
zhezhongyun 2025-05-02 14:46 5 浏览
最近手上维护的组件剩下的BUG都是表单验证,而且公司的表单验证那块代码经历的几代人,里面的逻辑开始变得不清晰,而且代码结构不是很angular。
是很有必要深入了解表单验证。
<body ng-controller="MainController"> <form name="form" novalidate="novalidate"> <input name="text" type="email" ng-model="name"> </form> </body>
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内容如下:
<form name="form" novalidate="novalidate"> <input name="text" type="email" ng-model="name" error-tip> </form>
指令代码如下:
// 当输入框出错,就显示错误 directive("errorTip",function($compile){ return { restrict:"A", require:"ngModel", link:function($scope,$element,$attrs,$ngModel){ //创建子scope var subScope = $scope.$new, //错误标签的字符串,有错误的时候,显示错误内容 tip = '<span ng-if="hasError">{{errors | json}}</span>'; //脏,而且无效,当然属于错误了 $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内容的。具体原理可以看这里
:http://www.cnblogs.com/accordion/p/5156553.html.
当有错误内容的时候,错误的元素就会显示。
为什么subScope可以访问hasError和errors方法?
因为原型链。
自定义错误内容
好了,很明显现在的表单验证是不能投入使用的,我们必须自定义显示的错误内容,而且要显示的错误不仅仅只有一个。
显示多个错误使用ng-repeat即可,也就是把"errorTip"指令中的
tip = '<span ng-if="hasError">{{errors | json}}</span>';
改成:
tip = '<ul ng-if="hasError" ng-repeat="(errorKey,errorValue) in errors">' + '<span ng-if="errorValue">{{errorKey | errorFilter}}</span>' + '</ul>';
其中errorFilter是一个过滤器,用于自定义显示错误信息的。过滤器其实是个函数。
其代码如下:
.filter("errorFilter",function{ return function(input){ var errorMessagesMap = { email:"请输入正确的邮箱地址", xxoo:"少儿不宜" } return errorMessagesMap[input]; } });
结果如下:
好了,到这里就能够处理“简单”的表单验证了。对,简单的。我们还必须继续深入。
自定义表单验证!
那我们就来实现一个不能输入“帅哥”的表单验证吧。
指令如下:
.directive("doNotInputHandsomeBoy",function($compile){ return { restrict:"A", require:"ngModel", link:function($scope,$element,$attrs,$ngModel){ $ngModel.$parsers.push(function(value){ if(value === "帅哥"){ //设置handsome为无效,设置它为无效之后,$error就会变成{handsome:true} $ngModel.$setValidity("handsome",false); } return value; }) } } })
结果如下:
这里有两个关键的东西,$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"
现在让我们实现自动首字母大写。
源码如下:
<form name="form" novalidate="novalidate"> <input name="text" type="text" ng-model="name" upper-case> </form>
.directive("upperCase",function{ return { restrict:"A", require:"ngModel", link:function($scope,$element,$attrs,$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,还是先看个例子吧.
<body ng-controller="MainController"> <form name="form" novalidate="novalidate"> <button ng-click="random">随机</button> <input name="text" type="text" ng-model="name" upper-case> </form> </body>
MainController的内容:
angular.module("app", []) .controller("MainController", function ($scope, $timeout) { $scope.random = function{ $scope.name = "hello" + Math.random; } })
够简单吧,点击按钮的时候,$scope.name变成hello开头的随机内容.
很明显,hello的首字母没大写,不是我们想要的内容。
我们修改下指令的内容:
.directive("upperCase",function{ return { restrict:"A", require:"ngModel", link:function($scope,$element,$attrs,$ngModel){ $ngModel.$parsers.push(function(value){ var viewValue = upperCaseFirstWord(handleEmptyValue(value)); //设置界面内容 $ngModel.$setViewValue(viewValue); //渲染到界面上,这个函数很重要 $ngModel.$render; return value; }) //当过外部设置modelValue的时候,会自动调用$formatters里面函数 $ngModel.$formatters.push(function(value){ return upperCaseFirstWord(handleEmptyValue(value)); }) //防止undefined,把所有的内容转换成字符串 function handleEmptyValue(value){ return angular.isUndefined(value) ? "" : "" + value; } //首字母大写 function upperCaseFirstWord(value){ return value.length > 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
-->刷新输入框内容
内容不完整的话,请拍砖,我继续加。
晚点补上源码剖析部分。
相关推荐
- 怎样关闭微软自带 Windows Defender 杀毒软件?
-
工欲善其事,必先利其器。专业的事需用专业工具,事半功倍。接下来,就为大家详细讲解如何关闭微软自带的WindowsDefender杀毒软件。1、点击左侧列表中的更新与安全选项。2、左上角安全中心,...
- 如何关闭360安全卫士(360杀毒和360安全卫士都要装吗?)
-
有时需暂时退出360安全卫士,该如何设置?1、右键点击电脑右下角的360安全卫士图标。2、点击退出按钮3、360安全卫士已停止运行。4、重复方法/步骤一的①、②部分。5、点按继续退出右侧的下...
- KMPlayer的视频解码器设置(kmplayerpro解码)
-
用KMPlayer64位播放视频时,如果出现无法打开或播放的问题,这通常与视频解码器有关。我们需要1、打开KMPlayer64位界面后,点击KMPlayer菜单选项。2、在菜单中点击选项3、...
- 探秘Win11任务栏“结束任务”按钮, 快速关闭无响应程序利器
-
IT之家4月20日消息,在日常使用Windows11时,我们偶尔会遇到应用程序或游戏无响应的情况,而此时窗口标题栏的“关闭”按钮也可能失效。以往,用户通常会通过打开任务管理器,手动查找并...
- 怎么修改密盘名称?(怎么修改密盘名称和密码)
-
如何更改超级秘密磁盘3000创建的加密盘名称?1、启动超级机密磁盘3000。2、在密盘中点击+号,接着选择重命名选项。3、输入密盘密码后,点击确定按钮。4、输入新密盘名称后,点击确定按钮。(9...
- QQ电脑管家使用技巧大全(qq电脑管家使用技巧大全)
-
QQ电脑管家是QQ医生3.3的升级版,功能更全面、智能且贴心。它涵盖安全防护、系统优化和软件管理,适合网民日常使用。1、安装完成后,打开QQ电脑管家,进入界面后点击系统优化选项。2、勾选清理垃圾、...
- 五一“12306候补”上热搜!如何提高候补兑现成功率?
-
4月17日已可购买五一当天车票,目前有不少旅客未购买到旅程车票,相关话题#12306候补#冲上热搜。有网友晒出自己车票候补等待兑现的截图,也有网友晒出“兑现成功”的截图并表示:“谁懂‘兑现成功’这四个...
- MSE显示"电脑状态:可能不受保护"怎么办
-
MSE是微软推出的一款实用的杀毒软件。不过,有些用户时常会遇到一个问题,MSE无缘无故提示电脑状态:可能不受保护。那么,当出现这种情况时,应该采取什么方法解决?1、我们发现,我的电脑状态显示可能不受...
- 应用程序无法正常启动0xc000007b如何解决?
-
打开某些应用程序时,可能会遇到的错误提示。很多人不清楚如何解决。实际上,这个问题源于电脑的DirectX9.0C出现故障。因此,只需针对DirectX9.0C进行修复即可解决问题。1、若要解决此...
- win7系统中MSE的解决方案不能自动更新
-
分享Win7系统MSE无法自动更新的解决方法,如下:检查服务状态,确保网络正常,手动更新尝试。1、MSE是一款免费杀毒软件。当局域网或网络异常导致无法连接服务器时,MSE在Win7系统中可能会出现无...
- Win7系统自带杀毒软件功能介绍(win7系统自带杀毒软件在哪里)
-
出于电脑系统安全的考量,微软在Win7中内置了自带的安全防护软件,这就是WindowsDefender(前身是WindowsAntiSpyware),也就是大家熟知的Win7自带杀毒工具,能够为用...
- Win7文件夹加密方法汇总(win7系统文件夹怎么加密)
-
Win7文件夹加密是大家关注的焦点。许多人意识到重要文件需要加密,但真正付诸行动的却很少,这往往导致信息丢失后追悔莫及。下面,我将结合个人经验,分享几种Win7文件夹加密的方法,希望能为大家提供实用的...
- Win7如何修复dll文件丢失问题?(win7官方dll修复工具)
-
Windows7小知识:电脑用户怎样解决dll文件缺失的问题?1、电脑用户开启电脑管家软件,其他安全软件亦有类似功能。2、启动程序后,点击界面右下角的工具箱功能按钮。3、打开工具箱功能界面,点击...
- 移动硬盘加密不再难,简单几步保护数据安全
-
移动硬盘资料存,总怕被人偷着看,觉得不安全?1、在软件左侧未加密的数据列表框中,选择要加密的文件或文件夹。2、若要对单个文件或文件夹加密,点击单个加密按钮;若为全盘加密,直接点击全盘加密。加密后的...
- 文件夹加密方法介绍:保护个人隐私的实用技巧
-
如何给文件夹加密?当电脑多人共用时,为保护个人隐私和防止资料泄露,通常会对重要文件夹进行加密处理(之前本站分享过巧用加密软件为文件夹加密的相关方法)。接下来,系统大侠小编将为大家介绍一种简单的文件夹加...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- HTML 参考手册 (28)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML常用标签 (29)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)