Angularjs Form form validation mechanism

Personal summary

one: 一般来讲表单可能遇到的问题
		1.如何数据绑定
	    2.验证表单
	    3.显示出错信息
	    4.整个form的验证
	    5.避免提交没有验证通过的表单
	    6.防止多次提交

two: input表单验证需要的属性
		* name   名字(这里需要注意:不光是input元素需要,最外层的form标签也需要一个name属性)
		* ng-model  绑定的数据
		* ng-required   是否必填 (true/false)
		* ng-minlength  最小长度
		* ng-maxlength  最大长度
		* ng-pattrn   匹配模式(正则匹配)
		* ng-change  值变化时的回调
		
three: 表单验证css样式
		* ng-valid   当表单验证通过时的设置
		* ng-invalid  当表单验证失败时的设置
		* ng-pristine  表单的未被动之前拥有
		* ng-dirty  表单被动过之后拥有
four: formName控制变量(返回的错误信息true/false);
		* formName.inputName.$pristine   字段是否未更改
		* formName.inputName.$dirty     字段是否更改
		* formName.inputName.$valid    字段有效
		* formName.inputName.$invalid   字段无效
		* formName.inputName.$error    字段错误信息(是一个对象,里面是每一个判断属性的bol值)
		这里的formName就是form标签上的name属性,inputName就是input标签上name属性,最后的$xxx则是angularjs内置的变量
		
five: Form的方法;
		* $setPristine 重置表单时可以用 将表单复位原始状态,包括class,$dirty,$pristine这三个方法
		  $scope.myForm.$setPristine(); $scope.myForm就是表单form标签的name,$setPristine()是它下面的一个重置方法

supplement

1. 省市三级联动select标签,可以写成
   <select class="form-control" ng-change="data.area = false" ng-model="data.province" ng-options="x.id as x.name for x in citys | cityFilter:0"></select>
   ng-options就是代替了<option value='x.id'></option>标签
   ng-options里的x.id as x.name for x in citys就是循环的city城市数组,x.id就是option的vaue值,x.name就是option显示的值
   
2. 自定义过滤器的一种用法(只是在本篇文章中的案例中涉及到了,在此粗略的总结一下,后面写到过滤器总结的时候会详细总结)
   var app=angular.module('app',[]);
   app.fliter('cityFilter',function(){
      //参数一,在循环后用的话就是默认当条数据,参数二,就是用过滤器时冒号后跟的参数
      // 例: ng-options="x.id as x.name for x in citys | cityFilter:0";  0就是第二个参数,第一个参数默认就是循环的当前数据
      return function(data,id){  
      var formData=[];
         // 在这里假设我们要过留下数据的id为0的;
         angular.forEach(data,function(v){
            if(v.id===id){
               formData.push(v);
            }
         })
      }
      return formData;
   })
   
3. 如果工作中用到的是这样的表单验证,submit提交时,可以用来控制提交按钮是否禁止
      例: <button type="submit" class="btn btn-default" ng-disabled="myForm.$invalid || data.hobbies === undefined || data.hobbies.length === 0">注册</button>
          前提是表单元素必须要加上ng-required='tru/e',checkbox除外,checkbox可以用逻辑来控制

4. ng-model;    //后面详细总结指令各个属性时在做详细总结,在此涉及一些
   * ng-model是angular原生的directive
   * 可以通过require ngModel可以更深的去处理数据的双向绑定
   * 使用方法:在directive指令中的require定义require:'ngModel'
     例:app.directive("directive", [ "$rootScope", function ($rootScope) {
	        return {
	            restrict: "E",
	            scope: {
	                changeCbk: "&",
	            },
	            require: "ngModel",  // 这个就是外面的ng-model绑定的数据
	            link: function (scope, element, attr, ngModelCtrl){
	                 ngModelCtrl就是ngModel
	            }
	        }
	     ]});
	* ngModel里的属性
	  & $parsers属性,保存了从viewValue向modelValue绑定过程中的处理函数,他们将来会依次执行
	  & $formatters,他保存的是从modelValue向viewValue绑定过程中的处理函数
	  & $setViewValue,当view发生了某件事情时,从view向model绑定调用
	    $setViewValue把viewValue保存下来
	  & $render 当模型发生变化时,应该怎么去更新视图,从model向view绑定
	     调用ctrl.$render方法,将viewValue渲染到页面上
	  & $setValidity 设置验证结果
	  & $viewValue 视图的值
	  & $modelValue 模型里的值

Case 1: Combined with bootstrap style, use angularjs's built-in verification function to achieve form verification.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="../../vendor/bootstrap3/css/bootstrap.min.css"/>
</head>
<body>
<div ng-app="myApp" style="margin-top: 100px;">
	<form name="myForm" action="kittencup.php" ng-controller="firstController" class="container form-horizontal">
        <div class="form-group" ng-class="{'has-error':myForm.username.$dirty && myForm.username.$invalid}">
            <label class="col-sm-2 control-label">用户名</label>
            <div class="col-sm-10">
                <input type="text" autocomplete="off" name="username" ng-pattern="/^[a-zA-Z]{1}/" ng-required="true" ng-minlength="5" ng-maxlength="10" ng-model="data.username" class="form-control" placeholder="用户名">
                <div ng-show="myForm.username.$dirty && myForm.username.$error.maxlength" class="alert alert-danger help-block">
                    用户名长度不能超过10位
                </div>
                <div ng-show="myForm.username.$dirty && myForm.username.$error.minlength" class="alert alert-danger help-block">
                    用户名长度不能小于5位
                </div>
                <div ng-show="myForm.username.$dirty && myForm.username.$error.pattern" class="alert alert-danger help-block">
                    用户名必须已英文字母开始
                </div>
            </div>
        </div>
        <div class="form-group" ng-class="{'has-error':myForm.password.$dirty && myForm.password.$invalid}">
            <label class="col-sm-2 control-label">密 码</label>
            <div class="col-sm-10">
                <input type="password" autocomplete="off" name="password" ng-required="true" ng-minlength="5" ng-maxlength="10" ng-model="data.password" class="form-control" placeholder="密码">
                <div ng-show="myForm.password.$dirty && myForm.password.$error.maxlength" class="alert alert-danger help-block">
                    密码长度不能超过10位
                </div>
                <div ng-show="myForm.password.$dirty && myForm.password.$error.minlength" class="alert alert-danger help-block">
                    密码长度不能小于5位
                </div>
            </div>
        </div>
        <div class="form-group" ng-class="{'has-error':myForm.passwordConfirm.$dirty && myForm.passwordConfirm.$invalid}">
            <label class="col-sm-2 control-label">确认密码</label>
            <div class="col-sm-10">
                <input type="password" autocomplete="off" name="passwordConfirm" ng-required="true" ng-model="data.passwordConfirm" class="form-control" placeholder="确认密码">
                <div ng-show="myForm.password.$dirty && myForm.passwordConfirm.$dirty && data.password !== data.passwordConfirm" class="alert alert-danger help-block">
                    密码和确认密码不一致
                </div>
            </div>
        </div>
        <div class="form-group" ng-class="{'has-error':myForm.email.$dirty && myForm.email.$invalid}">
            <label class="col-sm-2 control-label">邮箱</label>
            <div class="col-sm-10">
                <input type="email" autocomplete="off" name="email" ng-required="true" ng-minlength="5" ng-maxlength="30" ng-model="data.email" class="form-control" placeholder="邮箱">
                <div ng-show="myForm.email.$dirty && myForm.email.$error.maxlength" class="alert alert-danger help-block">
                    邮箱长度不能超过30位
                </div>
                <div ng-show="myForm.email.$dirty && myForm.email.$error.minlength" class="alert alert-danger help-block">
                    邮箱长度不能小于5位
                </div>
                <div ng-show="myForm.email.$dirty && myForm.email.$error.email" class="alert alert-danger help-block">
                    邮箱格式不正确
                </div>
            </div>
        </div>
        <div class="form-group" ng-class="{'has-error':myForm.blog.$dirty && myForm.blog.$invalid}">
            <label class="col-sm-2 control-label">博客网址</label>
            <div class="col-sm-10">
                <input type="url" autocomplete="off" name="blog" ng-required="true" ng-minlength="5" ng-maxlength="30" ng-model="data.blog" class="form-control" placeholder="博客网址">
                <div ng-show="myForm.blog.$dirty && myForm.blog.$error.maxlength" class="alert alert-danger help-block">
                    网址长度不能超过30位
                </div>
                <div ng-show="myForm.blog.$dirty && myForm.blog.$error.minlength" class="alert alert-danger help-block">
                    网址长度不能小于5位
                </div>
                <div ng-show="myForm.blog.$dirty && myForm.blog.$error.url" class="alert alert-danger help-block">
                    网址格式不正确
                </div>
            </div>
        </div>
        <div class="form-group" ng-class="{'has-error':myForm.age.$dirty && myForm.age.$invalid}">
            <label class="col-sm-2 control-label">年龄</label>
            <div class="col-sm-10">
                <input type="number" autocomplete="off" name="age" min="10" max="99" ng-required="true" ng-model="data.age" class="form-control" placeholder="年龄">
                <div ng-show="myForm.age.$dirty && myForm.age.$error.max" class="alert alert-danger help-block">
                    年龄不能超过99岁
                </div>
                <div ng-show="myForm.age.$dirty && myForm.age.$error.min" class="alert alert-danger help-block">
                    年龄不能小于10岁
                </div>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">性别</label>
            <div class="col-sm-10">
                <label class="radio-inline">
                    <input type="radio" ng-required="true" name="sex" ng-model="data.sex" value="1" /> 男
                </label>
                <label class="radio-inline">
                    <input type="radio" ng-required="true" name="sex" ng-model="data.sex" value="0" /> 女
                </label>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">爱好</label>
            <div class="col-sm-10">
                <label class="checkbox-inline" ng-repeat="hobby in hobbies">
                    <input type="checkbox" ng-model="hobby.checked" name="hobby[]" ng-checked="data.hobbies === undefined ? false : data.hobbies.indexOf(hobby.id) !== -1" ng-click="toggleHobbySelection(hobby.id)"/> {
   
   {hobby.name}}
                </label>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">出生地</label>
            <div class="col-sm-3">
                <select class="form-control" ng-change="data.area = false" ng-model="data.province" ng-options="x.id as x.name for x in cities | cityFilter:0"></select>
            </div>
            <div class="col-sm-3">
                <select class="form-control" ng-show="data.province" ng-model="data.area" ng-options="x.id as x.name for x in cities | cityFilter:data.province"></select>
            </div>
            <div class="col-sm-3">
                <select class="form-control" ng-required="true" ng-show="data.province && data.area" ng-model="data.city" ng-options="x.id as x.name for x in cities | cityFilter:data.area"></select>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">只能输入偶数</label>
            <div class="col-sm-10">
               <input type="text" name="even" class="form-group" placeholder="偶数" ng-model="data.even" even>
                <div ng-show="myForm.even.$error.even" class="alert alert-danger help-block">
                    数字必须是偶数
                </div>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">个人介绍</label>
            <div class="col-sm-10">
                <custom-text-area ng-model="data.introduct">aaa</custom-text-area>
                <custom-text-area ng-model="data.introduct"></custom-text-area>
            </div>
        </div>
        <div class="form-group">
           <div class="col-sm-offset-2 col-sm-10">
               <button type="submit" class="btn btn-default" ng-disabled="myForm.$invalid || data.hobbies === undefined || data.hobbies.length === 0">注册</button>
               <button type="reset" class="btn btn-default" ng-click="reset()">重置</button>
           </div>
        </div>
    </form>
</div>
<script type="text/javascript" src="../../vendor/angular/angularjs.js"></script>
<script type="text/javascript" src="app/index.js"></script>
</body>
</html>

Case 1: index.js

angular.module('myApp', [])

.filter('cityFilter', function () {
    return function (data, parent) {
        var filterData = [];
        angular.forEach(data, function (obj) {
            if (obj.parent === parent) {
                filterData.push(obj);
            }
        })
        return filterData;
    }
})

.directive('even',function(){
    return {
        require : 'ngModel',
        link:function(scope,elm,attrs,ngModelController){
            ngModelController.$parsers.push(function(viewValue){
                if(viewValue % 2 === 0){
                    ngModelController.$setValidity('even',true);
                }else{
                    ngModelController.$setValidity('even',false);
                }
                return viewValue;
            });
//                ngModelController.$formatters.push(function(modelValue){
//                    return modelValue + 'kittencup';
//                })
            }
        };
    })

.directive('customTextArea',function(){
    return {
        restrict:'E',
        template:'<div contenteditable="true"></div>',
        replace:true,
        require : 'ngModel',
        link:function(scope,elm,attrs,ngModelController){
            // view->model
            elm.on('keyup',function(){
                scope.$apply(function(){
                    ngModelController.$setViewValue(elm.html());
                });
            })
            ngModelController.$render = function(){
                elm.html(ngModelController.$viewValue);
            }

        }
    };
})


.controller('firstController', ['$scope', function ($scope) {
    var that = this;
    $scope.hobbies = [
        {id: 1,name: '玩游戏'},
        {id: 2,name: '写代码'},
        {id: 3,name: '睡觉'},
    ];
    $scope.cities = [
        {name: '上海',parent: 0,id: 1},
        {name: '上海市',parent: 1,id: 2},
        {name: '徐汇区',parent: 2,id: 8},
        {name: '长宁区',parent: 2,id: 3},
        {name: '北京',parent: 0,id: 4},
        {name: '北京市',parent: 4,id: 5},
        {name: '东城区',parent: 5,id: 6},
        {name: '丰台区',parent: 5,id: 7},
        {name: '浙江',parent: 0,id: 9},
        {name: '杭州',parent: 9,id: 100},
        {name: '宁波',parent: 9,id: 11},
        {name: '西湖区',parent: 100,id: 12},
        {name: '北仑区‎',parent: 11,id: 13}
    ];
    $scope.data = {
        hobbies: [1, 2],
        city: 3
    };
    
    // 先保留一份默认值
    $scope.origData = angular.copy($scope.data);
    $scope.reset = function(){
        $scope.data = angular.copy($scope.origData);
        that.initCity();
        console.log('aaaaaaaaaaaaaa-----',$scope.myForm);
        $scope.myForm.$setPristine();
    }

    // 让城市关联使用
    this.findCityId = function (parent) {
        var parentId;
        angular.forEach($scope.cities, function (city) {
            if (city.id === parent) {
                parentId = city.parent;
                return;
            }
        })
        return parentId;
    }

    this.initCity = function(){
        if ($scope.data.city !== undefined) {
            $scope.data.area = this.findCityId($scope.data.city);
            $scope.data.province = this.findCityId($scope.data.area);
        }
    }

    // 第一次打开页面 需要初始化一下
    this.initCity.call(this);

    $scope.toggleHobbySelection = function (id) {

        var index = -1;
        if ($scope.data.hobbies === undefined) {
            $scope.data.hobbies = [];
        } else {
            index = $scope.data.hobbies.indexOf(id);
        }

        if (index === -1) {
            $scope.data.hobbies.push(id);
        } else {
            $scope.data.hobbies.splice(index, 1);
        }

    }
}]);

Case 2: Same as Case 1, but the effect is different

<!DOCTYPE html>
<html lang="en" ng-app='App'>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>表单提示</title>
    <link rel="stylesheet" href="../../angularjs/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <style>
        body{
            padding-top: 50px;
        }
    </style>
</head>
<body>
    <div ng-controller="firstController" class="container">
        <div class="col-md-6">
            <form role="form" name="myForm" ng-submit="submitForm(myForm.$valid)" class="form-horizontal" novalidate>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="name">1.必填项</label>
                    </div>
                    <div class="col-md-8">
                        <input class="form-control" id="name" name="name" type="text" required ng-model='user.name' />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.name.$dirty && myForm.name.$valid"></span>
                    </div>
                </div>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="minlength">2.最小长度=5</label>
                    </div>
                    <div class="col-md-8">
                        <input type="text" id="minlength" name="minlength" ng-minlength="5" ng-model="user.minlength"
                            class="form-control" />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.minlength.$dirty && myForm.minlength.$valid"></span>
                    </div>
                </div>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="maxlength">3.最大长度=20</label>
                    </div>
                    <div class="col-md-8">
                        <input type="text" id="maxlength" name="maxlength" ng-model="user.maxlength" ng-maxlength="20"
                            class="form-control" />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.maxlength.$dirty && myForm.maxlength.$valid"></span>
                    </div>
                </div>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="pattern">4. 模式匹配</label>
                    </div>
                    <div class="col-md-8">
                        <input type="text" id="pattern" name="pattern" ng-model="user.pattern"
                            ng-pattern="/^[a-zA-Z]*\d$/" class="form-control" />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.pattern.$dirty && myForm.pattern.$valid"></span>
                    </div>
                </div>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="email">5. 电子邮件</label>
                    </div>
                    <div class="col-md-8">
                        <input type="email" id="email" name="email" ng-model="user.email" class="form-control" />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.email.$dirty && myForm.email.$valid"></span>
                    </div>
                </div>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="age">6. 数字</label>
                    </div>
                    <div class="col-md-8">
                        <input type="number" id="age" name="age" ng-model="user.age" class="form-control" />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.age.$dirty && myForm.age.$valid"></span>
                    </div>
                </div>
                <div class="form-group has-feedback">
                    <div class="col-md-4">
                        <label for="url"> 7. URL</label>
                    </div>
                    <div class="col-md-8">
                        <input type="url" id="url" name="url" ng-model="user.url" class="form-control" />
                        <span class="glyphicon glyphicon-ok form-control-feedback"
                            ng-show="myForm.url.$dirty && myForm.url.$valid"></span>
                    </div>
                </div>
                <div class="form-group text-center">
                    <input class="btn btn-primary btn-lg" ng-disabled="myForm.$invalid" type="submit" value="提交" />
                </div>
            </form>
        </div>
        <div class="col-md-12">
            1.必填项:{
   
   {user.name}}
            $pristine 【没修改】:{
   
   {myForm.name.$pristine }}
            $dirty【修改过】:{
   
   {myForm.name.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.name.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.name.$valid}}
            required:{
   
   {myForm.name.$error.required}}
            <br>
            2.最小长度=5:{
   
   {user.minlength}}
            $pristine 【没修改】:{
   
   {myForm.minlength.$pristine }}
            $dirty【修改过】:{
   
   {myForm.minlength.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.minlength.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.minlength.$valid}}
            $error【错误详情】:{
   
   {myForm.minlength.$error}} <br>
            3.最大长度=20:{
   
   {user.maxlength}}
            $pristine 【没修改】:{
   
   {myForm.maxlength.$pristine }}
            $dirty【修改过】:{
   
   {myForm.maxlength.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.maxlength.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.maxlength.$valid}}
            $error【错误详情】:{
   
   {myForm.maxlength.$error}} <br>
            4.模式匹配:{
   
   {user.pattern}}
            $pristine 【没修改】:{
   
   {myForm.pattern.$pristine }}
            $dirty【修改过】:{
   
   {myForm.pattern.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.pattern.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.pattern.$valid}}
            $error【错误详情】:{
   
   {myForm.pattern.$error}} <br>
            5.电子邮件:{
   
   {user.email}}
            $pristine 【没修改】:{
   
   {myForm.email.$pristine }}
            $dirty【修改过】:{
   
   {myForm.email.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.email.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.email.$valid}}
            $error【错误详情】:{
   
   {myForm.email.$error}} <br>
            6.数字:{
   
   {user.age}}
            $pristine 【没修改】:{
   
   {myForm.age.$pristine }}
            $dirty【修改过】:{
   
   {myForm.age.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.age.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.age.$valid}}
            $error【错误详情】:{
   
   {myForm.age.$error}} <br>
            7.URL:{
   
   {user.url}}
            $pristine 【没修改】:{
   
   {myForm.url.$pristine }}
            $dirty【修改过】:{
   
   {myForm.url.$dirty}}
            $invalid【验证失败】:{
   
   {myForm.url.$invalid}}
            $invalid【验证成功】:{
   
   {myForm.url.$valid}}
            $error【错误详情】:{
   
   {myForm.url.$error}} <br>
        </div>
    </div>
    <script src="../../angularjs/jquery-1.12.4.js"></script>
    <script src="../../angularjs/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <script src="../../angularjs/angular-1.5.8/angular.js"></script>
    <script>
        var app=angular.module('App',[]);
        app.controller('firstController',['$scope',function($scope){
            
        }])

    </script>
</body>
</html>

Guess you like

Origin blog.csdn.net/weixin_43996999/article/details/94973477