https://my.oschina.net/cokolin/blog/526911

摘要: 本文首发于 blog.csdn.net/vipshop_ebs/article/details/39472873 作者为本人,只是该博客暂停维护转到 OSC 了。 本文主要讲 AngularJS 的表单验证,Demo页面我使用 Bootstrap3.2.0 作为前端显示框架,同时引入了jQuery1.11.1,AngularJS 为刚刚新发布的1.2.25。

在新的项目中巧妙地接触到了Google提供的前端MVC框架 AngularJS,它的数据双向绑定真的能够让前端开发者从繁复的DOM操作中解放出来。

在我断断续续的学习AngularJS一个多月后,可以来讲讲我的 AngularJS 学习笔记了,当前首先要讲的是前端必不可少的元素——表单,以下用ng代替AngularJS,本文章适合有一定ng基础的同学。

Demo页面我使用Bootstrap3.2.0作为前端显示框架,同时引入了jQuery1.11.1,AngularJS 为刚刚新发布的1.2.25(使用1.3.0-rc2出现了一个奇怪的BUG,看来还是稳定版稳定),首先来一个大而全的表单页面:

因为整篇文章的字数限制,移到另一篇博客了:
http://my.oschina.net/cokolin/blog/526910

请忽略这个表单字段组合的合理性^_^。表单中,为所有字段绑定了ngModel,设置了校验指令,例如required,ngMinlength,ngMaxlength等,同时利用了ngShow、ngClass这两个指令来实现校验错误信息的提示。

在ngApp内定义一个form,实际上表示这个form已经被ng接管了,在相关的 ngController 的 $scope 域中会自动生成与这个form验证有关的字段,但是需要注意:

  1. 给 form 设置 name 属性才能使用ng的表单校验,可能设置了name,ng才会接管这个form;

  2. 给 form 设置 novalidate 属性是关闭浏览器内置的校验器,各个浏览器内置的校验器功能不一,也不够ng丰富,所以还是关了比较好;

  3. 避免给 form 设置 action 属性,设置了可能会导致表单不经校验直接提交的结果,当然也可以用其他方案解决这个问题;

  4. 给 form 设置 autocomplete="off" 是关闭浏览器的自动填写功能,这个功能有时候连按钮的disabled状态也记住了,可能会导致避免表单重复提交策略上的问题。

页面或CSS中可以通过 formName.inputFieldName.property 来访问表单字段的验证状态,主要有这几种状态:

  1. formName.inputFieldName.$pristine,Boolean类型,表单字段是否未修改;

  2. formName.inputFieldName.$dirty,Boolean类型,表单字段是否已修改;

  3. formName.inputFieldName.$valid,Boolean类型,表单字段是否验证通过;

  4. formName.inputFieldName.$invalid,Boolean类型,表单字段是否未通过验证;

  5. formName.inputFieldName.$error,Object类型,存储表单字段验证项的通过与否,例如
    formName.inputFieldName.$error.required,这个Boolean类型表示表单字段是否未通过必填的验证;

以上是默认的表单字段的验证状态,存储在$scope域中,表单自身也有这几个状态:

  1. formName.$pristine

  2. formName.$dirty

  3. formName.$valid

  4. formName.$invalid

ng会给表单元素加上一些校验相关的css,表单字段会根据验证状态添加这几个class:

  • .ng-valid

  • .ng-invalid

  • .ng-pristine

  • .ng-dirty

可以设置这些css的属性改变表单域的样式,例如设置:input.ng-invalid {border-color:red;},把未验证通过的表单元素边框设置为红色。

ng支持大部分的的HTML5表单类型,具体请查看ng的文档。表单中需要注意的几点:

  1. 如果在input绑定了ng-model,点击表单上的reset按钮并不会重置ng-model中绑定的数据,所以建议给reset按钮添加ng-click事件实现表单的重置;

  2. select 元素如果绑定了ng-model且无空值的option,那么ng会自动给select添加一个空option,在用户选择select的值以后,这个空 option会自动消失,所以为了显示方便,建议给相关的select添加一个value属性为空的option,例 如<optionvalue=""></option>,或者使用ng-init给绑定的ng-model初始化一个值;

  3. checkbox 或radio在用户点击后会优先执行浏览器给定的状态,所以可能会出现设置ng-checked失效的情况,例如给checkbox设置ng- checked="selectCount ==10",如果 $scope.selectCount 永远不等于10,但用户手动去点击这个checkbox,依然可以使这个checkbox处于选中状态,不过如果用户操作其他元素使 $scope.selectCount 的值改变还是会导致checkbox的状态变化的,我当前暂时未发现更优雅的解决方案,主要是给该checkbox添加ng-click事件,重复了 ng-checked 的检查代码,然后通过DOM操作重新设置了checkbox的状态;

表单字段的验证也可以自定义,在Demo的表单中,我自定义了一个重复密码校验的指令(my-pwd-match="myForm.password"):

myApp.directive('myPwdMatch', [function(){  
    return {  
        restrict: "A",  
        require: 'ngModel',  
        link: function(scope,element,attrs,ctrl){  
            var tageCtrl = scope.$eval(attrs.myPwdMatch);  
            tageCtrl.$parsers.push(function(viewValue){  
                ctrl.$setValidity('pwdmatch', viewValue == ctrl.$viewValue);  
                return viewValue;  
            });  
            ctrl.$parsers.push(function(viewValue){  
                if(viewValue == tageCtrl.$viewValue){  
                    ctrl.$setValidity('pwdmatch', true);  
                    return viewValue;  
                } else{  
                    ctrl.$setValidity('pwdmatch', false);  
                    return undefined;  
                }  
            });  
        }  
    };  
}]);

该自定义指令具体作用是:同时监听“用户密码”和”重复密码“两个字段的变化,根据用户的输入值的异同设置”重复密码“验证状态:

myForm.rpassword.$error.pwdmatch;

注意:重复密码输入框必须绑定ngModel才能使用这个指令。在ng的1.3.0-rc2版本上我定义这个指令在使用时发现ng无故给“重复密码”设置了一个验证状态:

myForm.rpassword.$error.parse;

暂不清楚这个是 BUG 还是1.2和1.3两个版本之间指令实现的差异。

上面这个是实时的本地验证,如果需要要实现字段的远端验证,一般验证的频率不会那么频繁,建议添加一些触发条件:

  • 当字段值长度等于多少时执行远端验证(这个比较适合图片验证码);

  • 延迟验证,就是等一两秒数据如果没有变化再执行验证;

  • 输入框丢失焦点后再触发验证(适合大部分输入框);

  • 用户点击提交按钮后再触发验证。

开发者可以使用这些远端验证中的一种或几种的组合,在确定输入框是否处于丢失焦点状态可以使用如下的指令:

myApp.directive('myFocusValid', [function(){  
    return {  
        restrict: "A",  
        require: 'ngModel',  
        link: function(scope,element,attrs,ctrl){  
            ctrl.$focused = false;  
            ctrl.$blured = true;  
            element.bind("focus", function(evt){  
                scope.$apply(function(){  
                    ctrl.$focused = true;  
                    ctrl.$blured = false;  
                });  
            }).bind("blur", function(evt){  
                scope.$apply(function(){  
                    ctrl.$focused = false;  
                    ctrl.$blured = true;  
                });  
            });  
        }  
    };  
}]);

该指令是给输入框校验器添加两个状态:$focused 和 $blured,为input添加 my-focus-valid 属性即可以使用这个指令。

不过我还是喜欢在用户点击按钮以后再使用远端验证,因为这样做可以避免在js中写复杂的阻止表单提交的逻辑,这个表单我使用ngSubmit指令,详细的实现请看controller:

myApp.controller("myCtrl", ["$scope", "$http", function($scope,$http){  
    console.log($scope)  
      
    $scope.safeTypes = [{  
        value: 0,  
        text: "不保存账户状态"  
    }, {  
        value: 30,  
        text: "保存半个小时"  
    }, {  
        value: 60,  
        text: "保存一个小时"  
    }, {  
        value: 180,  
        text: "保存三个小时"  
    }, {  
        value: 60 * 24,  
        text: "保存一天"  
    }, {  
        value: 60 * 24 * 7,  
        text: "保存一周"  
    }, {  
        value: 60 * 24 * 30,  
        text: "保存一个月"  
    }];  
  
    $scope.$watch("formArgs.username", function(newVal,oldVal){  
        var ctrl = $scope.myForm.username;  
        var usedNames = ctrl.$usedNames;  
        if(usedNames && usedNames[newVal]){  
            ctrl.$setValidity('remoted', false);  
        } else{  
            ctrl.$setValidity('remoted', true);  
        }  
    });  
  
    $scope.doSubmit = function(){  
        var username = $scope.formArgs ? $scope.formArgs.username : undefined;  
        var ctrl = $scope.myForm.username;  
        if(username){  
            $http({  
                method: 'POST',  
                url: 'json/check-username.json',  
                data: {  
                    username: username  
                }  
            }).success(function(resp){  
                if(resp.status != "success"){  
                    ctrl.$setValidity('remoted', false);  
                    if(ctrl.$usedNames){  
                        ctrl.$usedNames[username] = true;  
                    } else{  
                        var obj = {};  
                        obj[username] = true;  
                        ctrl.$usedNames = obj;  
                    }  
                } else{  
                    ctrl.$setValidity('remoted', true);  
                }  
                if($scope.myForm.$valid){  
                    alert("提交表单数据");  
                }  
            }).error(function(){  
                ctrl.$setValidity('remoted', false);  
            });  
        } else{  
            ctrl.$setValidity('remoted', true);  
        }  
        $scope.myForm.submitted = true;  
    }  
}]);

doSubmit事件中,我先判断用户名是否可以已被使用,然后再真正的执行表单的提交动作,同时也无论验证状态如何,都会设置表单的 submitted 状态为 true,让校验的结果能够在页面上快速的显示出来。

ng的1.2版本支持的表单元素主要是input、select、button、textarea, 其中input的type主要包括:text、hidden、password、checkbox、radio、file、image、reset、 submit和扩展的email、url、number,1.3版在1.2版的基础上又扩展了一些字段,包括:

  1. dateTimeLocal:yyyy-MM-dd'T'HH:mm:ss;

  2. date:yyyy-MM-dd;

  3. month:yyyy-MM;

  4. time:HH:mm:ss;

  5. week:yyyy-W##;

这些日期类型,所有的日期字段默认都是ISO的标准样式,但跟国内的习惯还是有一些差异,例如 dateTimeLocal中间多了一个字母T,week表示该年的第几周,例如2014-W49,这些日期类型的加入大大的增强了ng的功能,希望 1.3版本能够尽快的实现stable,不过不知道ng是否支持<input type="range">这个值域类型呢?

表单验证的效果图:

项目工程文件:

http://download.csdn.net/download/cackling/7954867

以后有时间会提供一下 git 项目地址。

作者:cackling

AngularJS 1.2.x 学习笔记(表单校验篇)的更多相关文章

  1. AngularJs轻松入门(六)表单校验

    表单数据的校验对于提高WEB安全性意义不大,因为服务器接收到的请求不一定来自我们的前端页面,有可能来自别的站点,黑客可以自己做一个表单,把数据提交到我们的服务器(即跨站伪造请求),这样就绕过了前端页面 ...

  2. AngularJs学习笔记-表单处理

    表单处理 (1)Angular表单API 1.模板式表单,需引入FormsModule 2.响应式表单,需引入ReactiveFormsModule   (2)模板式表单 在Angular中使用for ...

  3. php学习笔记——表单

    13.表单 1)GET vs. POST GET 和 POST 都创建数组(例如,array( key => value, key2 => value2, key3 => value ...

  4. [html5] 学习笔记-表单新增的元素与属性(续)

    本节主要讲解表单新增元素的controls属性.placeholder属性.List属性.Autocomplete属性.Pattern属性.SelectionDirection属性.Indetermi ...

  5. 9. Javascript学习笔记——表单处理

    9. 表单处理 9.1 表单的基础知识 ///表单用 <form> 元素表示,对应的是 HTMLFormElement 类型,继承自 HTMLElement. //属性:action.me ...

  6. JavaScript高级程序设计学习笔记--表单脚本

    提交表单 用户单击提交按钮或图像按钮时,就会提交表单.使用<input>和<button>都可以定义提交按钮,只要将其type特性的值设置为"submit" ...

  7. [html5] 学习笔记-表单新增元素与属性

    本节讲的是表单元素的form,formaction属性,frommethod,formenctype属性,formtarget,autofocus属性,required,labels属性. 1.for ...

  8. Vue.js学习笔记——表单控件实践

    最近项目中使用了vue替代繁琐的jquery处理dom的数据更新,个人非常喜欢,所以就上官网小小地实践了一把. 以下为表单控件的实践,代码敬上,直接新建html文件,粘贴复制即可看到效果~ <! ...

  9. bootstrap学习笔记(表单)

    1.基础表单 :对于基础表单,Bootstrap并未对其做太多的定制性效果设计,仅仅对表单内的fieldset.legend.label标签进行了定制. fieldset { min-width: 0 ...

随机推荐

  1. Visual Studio Team System 2008 Team Suite(90 天试用版)

    安装完成后,在“控制面板”中启动“添加删除程序”,选中Vs2008,点击“更改.删除”,输入序列号:PYHYP-WXB3B-B2CCM-V9DX9-VDY8T

  2. laravel/lumen 单元测试

    Testing Introduction Application Testing Interacting With Your Application Testing JSON APIs Session ...

  3. Mybatis原理分析之二:框架整体设计

    1.引言 本文主要讲解Mybatis的整体程序设计,理清楚框架的主要脉络.后面文章我们再详细讲解各个组件. 2.整体设计 2.1 总体流程 (1)加载配置并初始化       触发条件:加载配置文件 ...

  4. makefile函数

    http://www.cnblogs.com/tianyajuanke/archive/2013/02/16/2610276.html 通用步骤: 编译时,可以不知钉头文件,如果指定头文件,其作用是当 ...

  5. Java单例模式实现(线程安全)

    package com.javaee.corejava; /** * 线程安全的单例模式 * @author miaoyf * */ public class Singleton { /** * 私有 ...

  6. CentOS_7 OpenWrt Eclipse 环境搭建与 Dr.com 开发笔记

    一:内核的编译. 1,linux 编译环境的搭建与源码的准备工作 2,常用软件的安装 (make menuconfig) 3,  针对TP-Link WR740N 一些软件的openwrt 的移植 4 ...

  7. 使用Jenkins可持续集成maven项目

    首先下载最新的Jenkins的war包,放在tomcat的webapps的目录下,然后运行,例如: http://121.42.62.45:8080/jenkins/ 然后按照一步步的提示,下载相关的 ...

  8. d3安装异常

    使用npm安装D3,发现其工程名和依赖名重复,导致安装异常 http://thisdavej.com/node-newbie-error-npm-refusing-to-install-package ...

  9. HBase自动分区

    HBase扩展和负载均衡的基本单位是Region.Region从本质上说是行的集合.当Region的大小达到一定的阈值,该Region会自动分裂(split),当然也可能是合并(merge),合并可以 ...

  10. cocos2d触碰例子代码

    // // TestLayer.h // MiniTD // // Created by OnePiece on 12-7-30. // Copyright 2012年 __MyCompanyName ...