AngularJS - 表單驗證


雖然我不是前端程序員,但明白前端做好驗證是多么重要。
因為這樣后端就可以多喘口氣了,而且相比后端什么的果然還是前端可以提高用戶的幸福感。

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-messagesng-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-messasgesng-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指令的對象上發生focusblur事件時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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM