走进AngularJs(九)表单及表单验证
年底了越来越懒散,AngularJs的学习落了一段时间,博客最近也没更新。惭愧~前段时间有试了一下用yeoman构建Angular项目,感觉学的差不多了想做个项目练练手,谁知遇到了一系列问题。yeoman是基于node.js的一套工具包,由于我一直在windows下编程,而且node.js对于windows环境的支持也在慢慢加强,所以想尝试在windows下用yeoman跟搭建一个项目。过程远比想象的坎坷多了,各种报错,各种搜资料解决问题,最终还是无法解决一些编译出错,以失败告终,转战Linux。在此也提醒大家如果想在windows下使用yeoman,还是谨慎为好!
今天来学习一下一直被我忽视掉的表单验证。ng的强项是开发CRUD应用,也就是与用户操作多、交互比较频繁的应用。表单是与用户交互的一个重要角色,所以万万不能忽视。在学习之后发现这部分知识不仅仅是想象中的那么简单,比起其他特性,我们一直不怎么重视的表单验证,其实也可以做的很简单,而且易维护。下面就开始吧~
ng中的表单与Controller
看这个小标题也行你会差异,表单验证,怎么跟controller扯上关系了。ng中的form已经不同于我们平时用的form标签,做了增强。form是FormController的一个实例。如何理解这句话呢?想想我们使用ng-controller指令的情景:
<div ng-controller="testC">
<input type="test" ng-model="a" />
</div> <scritp>
function testC($scope){
//.............
}
</script>
应用了ng-controller的div就是testC的一个实例,我们可以在模板中使用定义在$scopt上的任何属性和方法,而testC的定义也是由我们自己实现的。当我们使用<form>的时候也是这样的道理,FormController由ng为我们定义好了,有一系列属性和方法提供给我们完成验证工作,form实例通过name属性来进行标识,我们可以通过此标识来访问form实例的属性和方法,如:
<form name="myform">
{{myform.$valid}}
</form>
form提供的属性都是用来表示表单的验证状态的,包括:$pristine(表单没有填写记录)、$dirty(表单有填写记录)、$valid(通过验证)、$invalid(未通过验证)、$error(验证错误信息)。除$error外,前四个的值为true或false表示相应的状态。$error的值为一个js对象,包含了以下验证内容的状态:
emailmaxmaxlengthminminlengthnumberpatternrequiredurl
这些内容我们会在稍后的例子中看到。FormController还提供了一些方法,我们一般不手工调用它们,都是系统自己调用。可参考官方文档:http://docs.angularjs.org/api/ng.directive:form.FormController
表单元素,如input、checkbox、radio等也不是普通的表单元素了,它们通通是NgModelController的实例。与form一样,也是通过name属性来标识。FormController拥有的那五个属性,NgModelController也同样拥有,除此之外,还有许多额外的属性和方法,我们稍后也在示例中展示,可参考官方文档:http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController
还有一个特性需要了解,一个表单中的表单元素,会作为这个form的属性自动加在上面,通过name标识就可以访问到,如:
<form name="myform">
<input type="text" name="myname" />
{{myform.myname.$valid}}
</form>
ng内置的验证规则
ng框架提供了非常方便的验证机制,你只需要在标签上加点指令,像使用HTML5提供的验证那样,然后在css中根据规则定义好正确/错误的样式就OK了,例如我们要让一个文本框为必填项,使用required:
<form name="myform novalidate>
<input type="text" ng-model="a" required />
</form>
有几点需要注意:
- 在<form>上加了一个novalidate,用来禁止掉浏览器默认的验证行为,因为ng已经对HTML5的几种表单新特性做了兼容处理。
- 表单元素必须有ng-model,否则无法触发验证
- 在css中分别定义.ng-pristine、.ng-valid、.ng-invalid、.ng-dirty这四种样式,ng会根据相应的状态自动加上样式。
这部分还是相当简单的,下面我们写例子来测一下这几种验证机制,HTML代码如下:
<div ng-app="MyApp">
<div ng-controller="testC">
<form name="myform" novalidate>
required: <input type="text" name="test1" ng-model="test1" required><br />
ng-minlength(3): <input type="text" name="test2" ng-model="test2" ng-minlength="3"><br />
ng-maxlength(10): <input type="text" name="test3" ng-model="test3" ng-maxlength="10"><br />
ng-pattern(/[a-f]/): <input type="text" name="test4" ng-model="test4" ng-pattern="/[a-f]/"><br />
type="number"(2-8): <input type="number" name="test5" max="8" min="2" ng-model="test5"><br />
type="url": <input type="url" name="test6" ng-model="test6"><br />
type="email": <input type="email" name="test7" ng-model="test7"><br />
</form>
<div>
<h2>表单验证结果:</h2>
myform.$invalid : {{myform.$invalid}}<br />
myform.$valid : {{myform.$valid}}<br />
myform.$pristine : {{myform.$pristine}}<br />
myform.$dirty : {{myform.$dirty}}<br />
myform.$error : {{myform.$error}}<br />
<h2>表单项验证结果</h2>
required:<br />
myform.test1.$invalid : {{myform.test1.$invalid}}<br />
myform.test1.$valid : {{myform.test1.$valid}}<br />
myform.test1.$pristine : {{myform.test1.$pristine}}<br />
myform.test1.$dirty : {{myform.test1.$dirty}}<br />
myform.test1.$error : {{myform.test1.$error}}<br />
myform.test2.$error : {{myform.test2.$error}}<br />
</div>
</div>
</div>
CSS代码,为不同的状态设置不同的背景色:
input.ng-pristine {
background-color: white;
}
input.ng-dirty {
background-color: lightyellow;
}
input.ng-valid {
background-color: lightgreen;
}
input.ng-invalid {
background-color: pink;
}
js代码,进行controller的初始化:
var app = angular.module('MyApp',[]);
app.controller('testC',function($scope){
$scope.test1='';
$scope.test2='';
$scope.test3='';
$scope.test4='';
$scope.test5='';
$scope.test6='';
$scope.test7='';
});
结果如下:
该示例编写在runjs上,点击查看http://runjs.cn/code/gspvlfrw
在上面的代码中,你也看到了我从FormConroller实例myform访问到的属性,还有从NgModelController访问到的属性。这些属性是非常有用的,比如你可以给表单的按钮加上:ng-disabled="myform.$invalid",这样在表单未通过验证的时候,提交按钮始终是不可点的。另外也可以根据表单元素的这些属性,来控制具体的错误提示信息,比如邮箱输错了,让"请输入正确的邮箱“这行字显示出来,如果你顺着我的思路,应该立马能想象到。
自定义验证规则
除了内置的这些验证规则,你还可以自己定义。方法就是写一个指令,加在表单元素上。听起来好简单的样子,但是这指令与一般的指令可不同,我们需要按一定的规则来写,这样才可以融入ng的验证机制,让你自定义的跟内置的一样可以便捷的工作和管理。这个时候,NgModelController提供的方法就派上用场了。我们从一个例子来开始吧。
我想让我的输入框只允许输入偶数,我们来定义一个名为even-num的指令,在页面上使用的时候像这样:
<input type="number" ng-model="test1" even-num />
完整的js代码如下:
var app = angular.module('MyApp',[]);
app.controller('testC',function($scope){
$scope.test1 = '';
});
app.directive('evenNum',function(){
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.push(function(viewValue) {
if (viewValue % 2 == 0) {
ctrl.$setValidity('evenNum', true);
return viewValue;
} else {
ctrl.$setValidity('evenNum', false);
return viewValue;
}
});
}
};
});
运行结果:
上面的例子编写在runjs上,点击查看http://runjs.cn/code/gdq8m0gb
现在来解释一下上面的代码。自定义指令的方式如果你不熟悉,可以先看一下我之前写的自定义指令部分。因为我们的指令要依赖NgModelController,所以写上了require:'ngModel',注意书写方式。 另外在link函数中,通过ctrl引用到了我们注入的NgModelController,然后向它的$parsers属性中push了一个函数进去。这个$parsers是什么东西呢?很明显它是一个数组,因为我们可以push东西进去。在解释之前,我们先清楚两个概念:我们把模板中的数据,像{{aa}}这样的,叫做viewValue,故名思义,视图中的数据。我们把模型/controller中的数据,叫做modelValue。ng所说的双向绑定,就是把这两者进行绑定。这个$parsers保存了从viewValue向modelValue绑定过程中的处理函数,它们将来会依次执行。因为我们的验证是从用户输入开始,即view发生了变化,所以我们的验证逻辑就加在这里。在验证结果中,我们调用ctrl.$setValidity方法,将结果保存,这样框架就能完成接下来的一系列工作。
与$parsers相对的,还有一个属性叫$formatters,它保存的是从modelValue向viewValue绑定过程中的处理函数。那我们定义的这个验证函数,要不要也push进$formatters里去呢?这取决于你的需要。如果你对两者的区别还不太清楚,看了下面这个例子就明白了:
上面的例子编写在runjs上,点击查看http://runjs.cn/code/9vde2r0w
两个input的ng-model指向的是同一个,所以数据会同步变化,但是$formatters里没有push进去验证函数,所以在从modelValue向ViewValue绑定的过程中,副本并没有进行验证。如果把验证函数push进$formatters,那么副本也会跟着验证了。
自定义表单元素
我们都知道,在表单元素上使用ng-model可以进行双向绑定。但是双向绑定只能用于input、checkbox这些标准表单控件上,你给一个div加ng-model是不能双向绑定的,因为系统不知道该如何绑定。所以话说过来,要想给非标准表单控件双向绑定,代码还得自己来写,说白了就是自定义一个指令。其实这部分内容放在自定义指令中也是合适的,但是官网在这里提到了,我也来介绍一下。
我们直接从例子开始,大家一定见过自适应的文本区域,就是随着输入内容的增加,会自动变高的textarea。用<textarea>标签做的话,需要加js代码才可以实现。更好的是纯css的方案,使用HTML5的新属性contenteditable,用一个div来模拟文本区域,div的高度默认就是自适应的,正好可以满足需求。基本的HTML代码和css代码如下:
<style>
.smarttextarea{
width: 400px;
min-height: 100px;
max-height: 400px;
border: 1px solid;
overflow: auto;
padding:5px 10px 20px;
}
</style>
<div contenteditable=”true" class="smarttextarea"></div>
我们现在要做的就是,让这个模拟出来的文本区域跟真正的textarea那样,可以进行数据的双向绑定,这样就可以进行验证了。我定义了一个名为smarttextarea的指令,使用起来像这样:
<smarttextarea contenteditable="true" class="smarttextarea" ng-model="test3" required></smarttextarea>
指令的定义如下:
app.directive('smarttextarea',function(){
var link = function(scope, elm, attrs, ctrl) {
//view=>model数据绑定
elm.bind('keyup', function() {
scope.$apply(function() {
ctrl.$setViewValue(elm.html());
});
});
//model=>view数据绑定
ctrl.$render = function() {
elm.html(ctrl.$viewValue);
};
ctrl.$setViewValue(elm.html());
};
return {
template : '<div></div>',
replace : true,
require: 'ngModel',
restrict: 'E',
link : link
};
});
看一下效果:
上面的例子编写在runjs上,点击查看http://runjs.cn/code/lhysp5vh
我给模拟出来的textarea加了required验证,可以发现生效了。其实关键代码就是进行了数据的双向绑定处理,包括两步:
- 从view向model绑定,监听keyup事件,然后调用ctrl.$setViewValue方法把viewValue保存下来
- 从model想view绑定,调用ctrl.$render方法,将viewValue渲染到页面上
经过这两步,我们就自定义了一个跟标准表单控件一样的元素,可以进行数据的双向绑定,表单验证通通没有问题。
走进AngularJs(九)表单及表单验证的更多相关文章
- 走进AngularJs 表单及表单验证
年底了越来越懒散,AngularJs的学习落了一段时间,博客最近也没更新.惭愧~前段时间有试了一下用yeoman构建Angular项目,感觉学的差不多了想做个项目练练手,谁知遇到了一系列问题.yeom ...
- AngularJS 表单提交后显示验证信息与失焦后显示验证信息
虽然说AngularJS的实时表单验证非常有用,非常高效方便,但是当用户还没有完成输入时便弹出一个错误提示,这种体验是非常糟糕的. 正常的表单验证逻辑应该是在用户提交表单后或完成当前字段中的输入后,再 ...
- AngularJS(五):表单及输入验证
本文也同步发表在我的公众号“我的天空” 表单基础 表单是HTML中很重要的一个部分,基本上我们的信息录入都依靠表单,接下来我们学习如何在AngularJS中使用表单,首先看以下示例代码: <bo ...
- SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页)
SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程,支持单表或多表结查集分页,存储过程如下: /******************/ --Author:梦在旅 ...
- EasyUI中在表单提交之前进行验证
使用EasyUi我们可以在客户端表单提交之前进行验证,过程如下:只需在onSubmit的时候使用return $("#form1").form('validate')方法即可,E ...
- Ajax实现提交表单时验证码自动验证(原创自Zjmainstay)
本文通过源码展示如何实现表单提交前,验证码先检测正确性,不正确则不提交表单,更新验证码. 1.前端代码 index.html <!DOCTYPE html> <html> &l ...
- Bootstrap 表单和图片 (内联表单,表单合组,水平排列,复选框和单选框,下拉列表,校验状态,添加额外的图标,控制尺寸,图片)
一.表单 基本格式 注:只有正确设置了输入框的 type 类型,才能被赋予正确的样式. 支持的输入框控件 包括:text.password.datetime.datetime-local.date.m ...
- JavaScript 客户端JavaScript之Document对象中的表单和表单元素
Form对象 代表一个HTML表单(document可以有多个表单元素) 表单访问 document.form[document.forms.length-1] 访问表单元素 document.for ...
- bootstrap 基础表单 内联表单 横向表单
bootstrap 基础表单 内联表单 横向表单 <!DOCTYPE html> <html> <head> <title></title> ...
随机推荐
- MySQLdb操作mysql的blob值
一般情况下我们是把图片存储在文件系统中,而只在数据库中存储文件路径的,但是有时候也会有特殊的需求:把图片二进制存入数据库. 今天我们采用的是python+mysql的方式 MYSQL 是支持把图片存入 ...
- MongoDB的真正性能-实战百万用户一-一亿的道具
使用情景 开始之前,我们先设定这样一个情景: 1.一百万注册用户的页游或者手游,这是不温不火的一个状态,刚好是数据量不上不下的一个情况.也刚好是传统MySql数据库性能开始吃紧的时候. 2.数据库就用 ...
- django中使用Profile扩展User模块(基于django 1.10版本下)
版本:Django 1.10.1(其他版本可能有不同的实现好解决办法) 参考官方文档:https://docs.djangoproject.com/en/1.10/topics/auth/custom ...
- oracle for loop循环以及游标循环
1. for in loop形式 DECLARE CURSOR c_sal IS SELECT employee_id, first_name || last_name ename, salar ...
- MFC - 微软基础类库和框架
一 MFC的概念和作用 1 什么是MFC?? 全称 Microsoft Foundation Class Library我们称之为微软基础类库 1)从硬盘的存在形式上来说 MFC就是一个库(静/动态库 ...
- 【Mail】搭建邮件服务器(LAMP+Postfix+Dovcot+PostfixAdmin+Roundcubemail)
大纲 一.mail部署说明 二.安装准备 三.LMAP环境配置 四.配置postfixadmin 五.配置postfix 六.配置dovecot 七.测试SMTP和POP3服务 八.配置Roundcu ...
- SharePoint 2013开发入门探索(一)- 自定义列表
在SharePoint 2013中创建自定义列表的方式有很多,在网站内容页面添加应用程序就可以创建(站点内容-〉 您的应用程序),也可以通过SharePoint Designer 2013创建,而本文 ...
- javascript code snippet -- 保留小数点位数
js1.5以上可以利用toFixed(x) ,可指定数字截取小数点后 x位 for example : //round "original" to two decimals var ...
- SRETAN
SRETAN (sretan.pas/c/cpp) 题目描述 4和7是幸运数字,输入k,输出第k个只含有4和7的数. 输入格式 一行一个数k 输出格式 一行一个数表示答案 样例输入 3 样例输出 44 ...
- npm ERR publish 403,nodejs发布包流程
nodejs学习体验之发布包,发布环境如下:1:win10系统,2:已安装nodejs. 具体操作步骤如下: *编写模块 1)新建文件夹,比如:somepackage 2) 该文件夹下新建js文件,比 ...