全栈工程师修炼ios程序员

angularjs+bootstrap 自定义表单验证

2016-08-12  本文已影响2216人  奶爸赚奶粉

本文使用angularjs及bootstrap,所需库请自行下载

目的

最终图

能够根据所需实现表单的验证,如果不符合需求,则弹出提示

1 建立相关文件

index.html

<!DOCTYPE html>
<html ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>form-error-message</title>
    <link rel="stylesheet" type="text/css" href="lib/bootstrap/css/bootstrap.min.css">
    <script type="text/javascript" src="lib/angular/angular.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="indexCtrl">
<form name="form"  class="form-horizontal">
    <div class="col-xs-8" >
        <div class="form-group" >
            <label class="col-xs-2 control-label">name:</label>
            <div class="col-xs-6">
                <input class="form-control" pattern="[0-9A-Za-z]{8,16}" title="输入的字符为8-16位" type="text" ng-model="name" name="name" required>
            </div>
        </div>
        <div class="col-xs-6 col-xs-offset-2">
            <button class="btn btn-danger" >确认</button>
        </div>
    </div>
</form>
</body>
</html

app.js

angular.module('app', []).controller('indexCtrl', ['$scope', function($scope){
    
}]);
基本样式

如上图,我门完成了基本的页面,页面中有一个输入框,验证规则为8-16位的字母及数字

2 创建指令

创建一个指令,本文为了方便,我写在了app.js中

angular.module('app').directive('errorMessage', ['$compile', function($compile) {
    // Runs during compile
    return {
        restrict: 'A',
        require: 'ngModel', 
        link: function(scope, element, attr, ngModel) {

            var subScope = scope.$new(true);
            
            var parenNode = element.parent();
            parenNode.addClass("has-feedback");

            var errorElement = $compile(`
                <span class="glyphicon glyphicon-warning-sign form-control-feedback" ></span>
                <ul class="help-block" >
                    
                </ul>
                `)(subScope);

            element.after(errorElement)
        }
    };
}]);

在上文中,我们创建了一个errorMessage指令。
它里面创建了一个subScope作用域用来跟当前作用域做隔离。
在input的上一层,我们加了一个has-feedback的class,用来配合之后的feedback提示。
最后我们创建了一段html并把它插入到input之后

此处使用了es6的书写方式` `,es5 请使用字符串拼接的方式书写。
然后我们在html的input中使用该指令

<input class="form-control" error-message pattern="[0-9A-Za-z]{8,16}" title="输入的字符为8-16位" type="text" ng-model="name" name="name" required>

最终效果如下

Paste_Image.png

3 添加交互效果

现在页面中需要加入效果,判定当前输入框的结果,输入框不符合规则的,需要显示出异常

表单中,会自动把表单的相关内容绑定到一个以表单名字命令的局部作用域变量中,我们可以用过$scope.formName来获取,文中使用了name="form" ,可以使用$scope.form来获取该表单

在html5中,如果在一个表单内点击button按钮,会自动触发html5的验证规则,会出现如下图的样式

Paste_Image.png

但是我们不希望自动弹出这个,所以我们把form改成ng-form来规避此问题
将html的form改为ng-form

当前的input输入框,已经绑定了一个$scope.form.inputName的变量,这个变量用于验证表单。我们的名字为 name="name"
,当前input的值就绑定到了 $scope.form.name的变量上

在指令中,我们引入了ng-model,ng-model已经自动绑定了$scope.form.name这个变量。我门主要是用ng-model的$invalid$dirty,前者用于判断是否有修改过的表单,后者判断表单的内容是否不合法,两者的值都是boolean类型

在指令中追加如下内容

subScope.hasError=function(){
    var re=ngModel.$invalid&&ngModel.$dirty;
if(re){
    parenNode.addClass("has-error");
}else{
    parenNode.removeClass("has-error");
}
    return re;
}

subScope.errors=function(){
    return ngModel.$error;
}

hasError函数用于验证当前输入状态,如果已经输入过并且目前验证有异常,则返回true,并把父元素增加has-errorclass
errors 用于返回当前爆出的异常内容,其中返回的ngModel.$error为一个对象,里面列出了没有通过验证的内容的key

然后我们在追加的元素中增加这两个内容


var errorElement = $compile(`
                <span   ng-if="hasError()"  class="glyphicon glyphicon-warning-sign form-control-feedback" ></span>
                <ul class="help-block" ng-if="hasError()">
                    <li ng-repeat="(error,wrong) in errors()" ng-bind="error">
                </ul>
                `)(subScope);
Paste_Image.png

目前已经能正确的显示异常和非异常的状态了,但是目前是英文的,我门需要加一个中文的信息库

先在指令中添加
scope:{ title:'@' }
用于将input上标示的title属性引入进来
修改后指令如下

angular.module('app').directive('errorMessage', ['$compile', function($compile) {
    // Runs during compile
    return {
        restrict: 'A',
        scope:{
            title:'@'
        },
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {

    ...
            }
    };
}]);

然后在link中添加中文字符串属性

            subScope.errorsText={
                required:"此项为必填",
                pattern:scope.title
            }

并在追加的element中使用

var errorElement = $compile(`
                <span   ng-if="hasError()"  class="glyphicon glyphicon-warning-sign form-control-feedback" ></span>
                <ul class="help-block" ng-if="hasError()">
                    <li ng-repeat="(error,wrong) in errors()" ng-bind="errorsText[error]">
                </ul>
                `)(subScope);

最终效果如下

未输入 验证不通过 必填 验证通过

截止目前的代码

index.html


<!DOCTYPE html>
<html ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>form-error-message</title>
    <link rel="stylesheet" type="text/css" href="lib/bootstrap/css/bootstrap.min.css">
    <script type="text/javascript" src="lib/angular/angular.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="indexCtrl">
<ng-form name="form"  class="form-horizontal">
    <div class="col-xs-8" >
        <div class="form-group" >
            <label class="col-xs-2 control-label">name:</label>
            <div class="col-xs-6">
                <input class="form-control" error-message pattern="[0-9A-Za-z]{8,16}" title="输入的字符为8-16位" type="text" ng-model="name" name="name" required>
            </div>
        </div>
        <div class="col-xs-6 col-xs-offset-2">
            <button class="btn btn-danger" >确认</button>
        </div>
    </div>
</ng-form>
</body>
</html

app.js

angular.module('app', []).controller('indexCtrl', ['$scope', '$http', function($scope, $http) {

}]);

angular.module('app').directive('errorMessage', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope:{
            title:'@'
        },
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {

            var parenNode = element.parent();
            parenNode.addClass("has-feedback");


            var subScope = scope.$new(true);
            subScope.errorsText={
                required:"此项为必填",
                pattern:scope.title
            }

            subScope.hasError=function(){
                var re=ngModel.$invalid&&ngModel.$dirty;
                if(re){
                    parenNode.addClass("has-error");
                }else{
                    parenNode.removeClass("has-error");
                }
                return re;
            }

            subScope.errors=function(){
                return ngModel.$error;
            }


            var errorElement = $compile(`
                <span   ng-if="hasError()"  class="glyphicon glyphicon-warning-sign form-control-feedback" ></span>
                <ul class="help-block" ng-if="hasError()">
                    <li ng-repeat="(error,wrong) in errors()" ng-bind="errorsText[error]">
                </ul>
                `)(subScope);

            element.after(errorElement)
        }
    };
}]);

4 增加提交交互

目前我们大部分的问题都解决了,但是还剩下一个问题,我们在点击button的时候,希望把所有验证错误的内容都显示出来

我们可以借助form$submitted属性,这个属性,在表单中点击过提交会变为true,否则为false。
我们在button按钮上添加提交的点击事件

<button class="btn btn-danger" ng-click="submit()">确认</button>

然后在当前控制器中添加该事件

angular.module('app', []).controller('indexCtrl', ['$scope', function($scope) {
    $scope.submit=function(){
        if(!$scope.form.$invalid){
            alert("验证通过")
        }else{
            $scope.form.$setSubmitted(true);
        }
    }
}]);

然后在指令的hasError函数中添加

subScope.hasError=function(){
    var re=(ngModel.$$parentForm.$submitted||ngModel.$dirty)&&ngModel.$invalid;
    ...
}

表示在表单提交的时候,无论是否输入过都显示出异常
最终效果如下:

最终效果

5 最终代码

index.html

<!DOCTYPE html>
<html ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>form-error-message</title>
    <link rel="stylesheet" type="text/css" href="lib/bootstrap/css/bootstrap.min.css">
    <script type="text/javascript" src="lib/angular/angular.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="indexCtrl">
<ng-form name="form"  class="form-horizontal">
    <div class="col-xs-8" >
        <div class="form-group" >
            <label class="col-xs-2 control-label">name:</label>
            <div class="col-xs-6">
                <input class="form-control" error-message pattern="[0-9A-Za-z]{8,16}" title="输入的字符为8-16位" type="text" ng-model="name" name="name" required>
            </div>
        </div>
        <div class="col-xs-6 col-xs-offset-2">
            <button class="btn btn-danger" ng-click="submit()">确认</button>
        </div>
    </div>
</ng-form>
</body>
</html

app.js

angular.module('app', []).controller('indexCtrl', ['$scope', '$http', function($scope, $http) {
    $scope.submit=function(){
        if(!$scope.form.$invalid){
            alert("验证通过")
        }else{
            $scope.form.$setSubmitted(true);
        }
    }
}]);

angular.module('app').directive('errorMessage', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope:{
            title:'@'
        },
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {

            var parenNode = element.parent();
            parenNode.addClass("has-feedback");


            var subScope = scope.$new(true);
            subScope.errorsText={
                required:"此项为必填",
                pattern:scope.title
            }

            subScope.hasError=function(){
                var re=(ngModel.$$parentForm.$submitted||ngModel.$dirty)&&ngModel.$invalid;
                if(re){
                    parenNode.addClass("has-error");
                }else{
                    parenNode.removeClass("has-error");
                }
                return re;
            }

            subScope.errors=function(){
                return ngModel.$error;
            }


            var errorElement = $compile(`
                <span   ng-if="hasError()"  class="glyphicon glyphicon-warning-sign form-control-feedback" ></span>
                <ul class="help-block" ng-if="hasError()">
                    <li ng-repeat="(error,wrong) in errors()" ng-bind="errorsText[error]">
                </ul>
                `)(subScope);

            element.after(errorElement)
        }
    };
}]);
上一篇 下一篇

猜你喜欢

热点阅读