AngularJS实现表单验证


Posted in Javascript onJanuary 28, 2015

虽然我不是前端程序员,但明白前端做好验证是多么重要。

因为这样后端就可以多喘口气了,而且相比后端什么的果然还是前端可以提高用户的幸福感。

AngularJS提供了很方便的表单验证功能,在此记录一番。

首先从下面这段代码开始

<form ng-app="myApp" ng-controller="validationController" name="mainForm" novalidate>

    <p>Email:

        <input type="email" name="email" ng-model="email" required>

        <span style="color:red" ng-show="mainForm.email.$dirty && mainForm.email.$invalid">

            <span ng-show="mainForm.email.$error.required">Email is required.</span>

            <span ng-show="mainForm.email.$error.email">Invalid email address.</span>

        </span>

    </p>

    <p>

        <input type="submit" ng-disabled="mainForm.$invalid">

    </p>

</form>

<script>

angular.module('myApp',[])

.controller('validationController', ['$scope',function($scope) {

    $scope.user = 'Kavlez';

    $scope.email = 'sweet_dreams@aliyun.com';

}]);

</script>

input标签的一些验证选项,通常和HTML5标记搭配使用。

必填

<input type="text" required />
长度

使用指令ng-minlength/ng-maxlength

<input type="text" ng-minlength="5" />
特定格式
例如电子邮件、URL、数字,将type设置为相应类型即可,例如:

<input type="email" name="email" ng-model="user.email" />

<input type="number" name="age" ng-model="user.age" />

<input type="url" name="homepage" ng-model="user.facebook_url" />

模式匹配

使用指令ng-pattern,例如:

<input type="text" ng-pattern="[a-z]" />

表单属性,通过这些属性可以更容易地对表单进行操作

pristine/dirty
表示是否已修改,例如

<form name="mainForm" ng-controller="orderController">

<input type="email" name="userEmail" ng-model="myEmail" />

    {{mainForm.userEmail.$pristine}}

    {{mainForm.userEmail.$dirty}}

</form>

以formName.fieldName.$pristine方式访问,input必须有ng-model声明。

valid/invalid

表示是否通过验证。

$error

表单验证信息,验证不通过时返回相应信息。

AngularJS为表单状态提供了相应地css class

.ng-pristine

.ng-dirty

.ng-valid

.ng-invalid

例如,让验证通过为绿色,失败为红色:

input.ng-valid {

    color: green;

}

input.ng-invalid {

    color: green;

}

给出的例子中仅仅是一个email的验证就写了这么多,如果再加几个field,再加几种不同的提示,再加上几个事件,代码会变得杂乱不堪。

事实上并不推荐这样做,我们有更好的方法。
就是使用angular-messages.js

首先,不要忘了这两步

<script src="angular-messages.js"></script>

angular.module('myApp', ['ngMessages'])

好,先用ng-messages和ng-message替换掉那些重复的东西,上面的例子变成:

<form ng-controller="validationController" name="mainForm" >

    <p>Email:

        <input 

        type="email" name="email" ng-model="myEmail" ng-minlength="3" ng-maxlength="50" required />

        <div style="color:red" ng-messages="mainForm.email.$error" ng-messages-multiple>

            <p class="error" ng-message="required">Email is required.</p>

            <p class="error" ng-message="email">Invalid email address.</p>

            <p class="error" ng-message="minlength">min length 10</p>

            <p class="error" ng-message="maxlength">max length 50</p>

        </div>

    </p>

    <p>

        <input type="submit" ng-disabled="mainForm.$invalid" />

    </p>

</form>

功能上没有任何变化,只是把重复的代码全部去掉了。
注意区分ng-messasges和ng-message,有没有感觉有点像with()? 后面的ng-messages-multiple,这里用作同时让多个提示出现。

但这样仍然不够好,就算省去了ng-message中的内容,但是多个field中都存在required验证时仍然会有重复。
而且,如果不同页面中的表单都涉及到相同的内容时重复的验证提示会越来越多。
为了解决这个问题,我们可以使用ng-messages-include指令。
该指令用来引用模板,比如上面的例子变为:

<form ng-controller="validationController" name="mainForm" >

    <p>Email:

        <input 

        type="email" name="email" ng-model="myEmail" ng-minlength="3" ng-maxlength="50" required />

        <div style="color:red" ng-messages="mainForm.email.$error" ng-messages-multiple ng-messages-include="validateTemplate/email.html">

        </div>

    </p>

    <p>

        <input type="submit" ng-disabled="mainForm.$invalid" />

    </p>

</form>

并不复杂,我们再加点东西。
为了让提示更友好(?)一些,我们试试实现光标离开后出现提示的效果。
这时候用指令(directive)会方便很多,在这里先涉及一点和指令相关的内容。

先运行起来再说:

var myApp = angular.module('myApp',[])

    .controller('validationController', ['$scope',function($scope) {

        $scope.user = 'Kavlez';

        $scope.email = 'sweet_dreams@aliyun.com';

    }])

    .directive('hintOnBlur', [function() {

        return {

            require: 'ngModel',

            link: function(scope, element, attrs, ctrl) {

                ctrl.focused = false;

                element.bind('focus', function(evt) {

                    scope.$apply(function() {ctrl.focused = true;});

                }).bind('blur', function(evt) {

                    scope.$apply(function() {ctrl.focused = false;});

                });

            }

        }

    }]);

此处我们用focused来判断光标是否在某个属性上,当使用了hintOnBlur指令的对象上发生focus或blur事件时focused的状态发生变化。

表单也跟着改变一下,使用方法如下:

<form ng-controller="validationController" name="mainForm" >

    <p>Email:

        <input type="email" name="email" ng-model="myEmail" ng-minlength="3" ng-maxlength="50" required hint-on-blur />

        <div style="color:red" ng-messages="mainForm.email.$error" ng-show="!mainForm.email.focused" ng-messages-multiple ng-messages-include="validateTemplate/email.html">

        </div>

    </p>

    <p>

        <input type="submit" ng-disabled="mainForm.$invalid" />

    </p>

</form>

在ng-show中再加入对focused的判断,false时出现提示。

现在看起来像那么回事了。
自定义验证方式与有效性(validity),这个也用到指令(directive)。
验证填写的email是否已占用,这里简单模拟一下:

.directive('isAlreadyTaken', function() {

    return {

        require: 'ngModel',

        link: function(scope, ele, attrs, ctrl) {

            ctrl.$parsers.push(function(val) {

                ctrl.$setValidity('emailAvailable', false);

                var emailTable = [

                    'K@gmail.com',

                    'a@gmail.com',

                    'v@gmail.com',

                    'l@gmail.com',

                    'e@gmail.com',

                    'z@gmail.com'];

                for (var i=0;i<emailTable.length;i+=1)

                    if(val==emailTable[i])

                        return;

                ctrl.$setValidity('emailAvailable', true);

                return val;

            })

        }

    }

})

Input元素中加上is-already-taken属性,并且再加一个ng-message:

<p class="error" ng-message="emailAvailable">Already taken! try other email addresses!</p>
Javascript 相关文章推荐
跨浏览器的事件对象介绍
Jun 27 Javascript
extjs_02_grid显示本地数据、显示跨域数据
Jun 23 Javascript
JavaScript几种数组去掉重复值的方法推荐
Apr 12 Javascript
基于jquery实现智能表单验证操作
May 09 Javascript
JS 日期与时间戮相互转化的简单实例
Jun 22 Javascript
图文详解JavaScript的原型对象及原型链
Aug 02 Javascript
利用jquery去掉时光轴头尾部线条的方法实例
Jun 16 jQuery
微信小程序 蓝牙的实现实例代码
Jun 27 Javascript
JavaScript使用math.js进行精确计算操作示例
Jun 19 Javascript
Vue Echarts实现可视化世界地图代码实例
May 07 Javascript
Vue watch响应数据实现方法解析
Jul 10 Javascript
Vue CLI中模式与环境变量的深入详解
May 30 Vue.js
jQuery制作简单柱状图实例
Jan 28 #Javascript
js分页工具实例
Jan 28 #Javascript
js制作简易年历完整实例
Jan 28 #Javascript
Angularjs编写KindEditor,UEidtor,jQuery指令
Jan 28 #Javascript
调试JavaScript中正则表达式中遇到的问题
Jan 27 #Javascript
JavaScript插件化开发教程 (四)
Jan 27 #Javascript
JavaScript插件化开发教程 (三)
Jan 27 #Javascript
You might like
自己在做项目过程中学到的PHP知识收集
2012/08/20 PHP
PHP使用PHPMailer发送邮件的简单使用方法
2013/11/12 PHP
json的键名为数字时的调用方式(示例代码)
2013/11/15 PHP
php的zip解压缩类pclzip使用示例
2014/03/14 PHP
Mozilla 表达式 __noSuchMethod__
2009/04/05 Javascript
javascript中的数字与字符串相加实例分析
2011/08/14 Javascript
javascript中DOM复选框选择用法实例
2015/05/14 Javascript
浅谈Javascript数组的使用
2015/07/29 Javascript
bootstrapValidator自定验证方法写法
2016/12/01 Javascript
详解vue.js全局组件和局部组件
2017/04/10 Javascript
vue文件树组件使用详解
2018/03/29 Javascript
如何测量vue应用运行时的性能
2019/06/21 Javascript
JS代码屏蔽F12,右键,粘贴,复制,剪切,选中,操作实例
2019/09/17 Javascript
vue实现Input输入框模糊查询方法
2021/01/29 Javascript
在antd中setFieldsValue和defaultVal的用法
2020/10/29 Javascript
[53:03]Optic vs TNC 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Django集成百度富文本编辑器uEditor攻略
2014/07/04 Python
Django Admin实现三级联动的示例代码(省市区)
2018/06/22 Python
python中的json总结
2018/10/11 Python
Python3实现二叉树的最大深度
2019/09/30 Python
Python实现图像的垂直投影示例
2020/01/17 Python
python3.6使用SMTP协议发送邮件
2020/05/20 Python
Kmeans均值聚类算法原理以及Python如何实现
2020/09/26 Python
CSS3教程(9):设置RGB颜色
2009/04/02 HTML / CSS
BOSE德国官网:尽探索之力,享音乐之极
2016/12/11 全球购物
美国第一个网上卖鞋零售商:OnlineShoes.com
2017/09/24 全球购物
DogBuddy荷兰:找到你最完美的狗保姆
2019/04/17 全球购物
几道数据库的面试题或笔试题
2014/05/31 面试题
Linux文件系统类型
2012/02/15 面试题
企业演讲比赛主持词
2014/03/18 职场文书
北京申奥口号
2014/06/19 职场文书
安全生产感想
2015/08/07 职场文书
2016领导干部廉洁自律心得体会
2016/01/13 职场文书
2017新年晚会开幕词
2016/03/03 职场文书
Springboot使用Spring Data JPA实现数据库操作
2021/06/30 Java/Android
python scrapy简单模拟登录的代码分析
2021/07/21 Python