AngularJS 表單驗證

在使用 AngularJS 進行開發的時候,表單填寫是一個很常見的需求,而表單驗證又是比較讓人頭疼的部分,本文對此作一個總結。javascript

在 Angular 的視圖中使用的 form 已經不是 HTML 中的普通 form 了,而是一個被 Angular 封裝過的指令。它能夠完成普通 form 沒法實現的功能,好比 form 嵌套,並且自帶強大的驗證功能。css

Angular 在對錶單進行校驗的時候會使用 ngModelController 上的屬性,若是不設置 ng-model,則 Angular 沒法知道 form.$invalid 這個值是否爲真。後面在自定義驗證有對它的介紹。html

本文在對錶單的驗證時使用了 ng-messages,在文章最後也有對它的介紹。java

本文涉及到的源碼在 這裏,實現效果在 這裏git

原生表單驗證

在 form 層面,可使用 ng-disabled 來控制提交按鈕的狀態,在 form 表單項所有驗證經過前不可點擊,下面介紹一下通用的表單項驗證選項。angularjs

input 驗證選項

AngularJS 的 input 標籤 自帶的驗證選項有如下這些。github

<input
  ng-model=""
  [name=""]
  [required=""]
  [ng-required=""]
  [ng-minlength=""]
  [ng-maxlength=""]
  [ng-pattern=""]
  [ng-change=""]>
...
</input>

a. 必填api

<input type="text" name="myName" ng-model="username" required />

使用 ng-required 能夠根據後面表達式的值設置是否 requiredpromise

在不知足 requiredform.myName.$error{required: true}app

b. 長度

<input type="text" name="myName" ng-model="username" ng-minlength="2" ng-maxlength="10" />

在不知足 ng-minlength/ng-maxlengthform.myName.$error{minlength: true, maxlength: true}

直接使用 minlength/maxlength 也有相同效果,並且 maxlength 能夠設置最多輸入 x 個字符,超過以後沒法再輸入。

c. 模式匹配

<input type="text" name="myDesc" ng-model="desc" ng-pattern="/^[a-zA-Z]{1,20}$/" />

在不知足 ng-patternform.myName.$error{pattern: true}

d. 其餘

AngularJS 對特定格式也進行了校驗。好比將 type 設置爲 urlemail 等,在沒有特殊驗證要求的狀況下,能夠直接使用這些自帶的校驗,或者經過自定義指令修改 Angular 內建驗證器。不一樣 type 有不一樣的驗證選項,具體參考 AngularJS API 文檔

CSS Classes

Angular 會根據表單狀態自動給表單和表單項添加如下幾組樣式:

  • ng-valid 驗證經過,與之相對的是 ng-invalid

  • ng-valid-[key] 經過自定義驗證器添加的驗證經過的值,與之相對的是 ng-invalid-[key]

  • ng-pristine 未交互狀態,與之相對的是 ng-dirty

  • ng-touched 未訪問狀態,與之相對的是 ng-untouched

  • ng-pending 知足 $asyncValidators 的狀況

這些在 ngModelController 的屬性中都有對應值。

根據這些 class,能夠爲不一樣狀態設置不一樣的樣式,好比這樣:

input.ng-valid.ng-dirty {
    border-color: #78FA89;
}

input.ng-invalid.ng-dirty {
    border-color: #FA787E;
}

自定義驗證

AngularJS 指令入門 一文中,提到過經過 require 屬性和 controller 參數,能夠實現指令之間的交互。那麼,在自定義指令中使用 require: 'ngModel' 就可使用 ngModel 指令的 controller 屬性的實例了。

ngModelController

ngModel 提供了數據綁定、驗證、CSS更新、數據格式化和編譯等操做。下面簡單介紹一下 ngModelController 經常使用的屬性和方法。

核心屬性

  1. $viewValue 視圖裏的值

  2. $modelValue 數據模型裏值

input 事件觸發的時候,$viewValue 會同步到 $modelValue 。默認狀況下,這個是一旦 input 中的內容有改變就觸發。AngularJS 1.3 引入了 ng-model-options,可讓這個同步延遲到 blur 或者延遲必定的時間以後。

<input type="text" name="username" ng-model="username" ng-model-options="{updateOn:'blur'}">
<input type="text" name="username" ng-model="username" ng-model-options="{ debounce: 500 }">

$viewValue 的值同步到 $modelValue 時,會通過 $parsers$validators$asyncValidators 三個核心管道(後兩個是 AngularJS 1.3 之後新加的)進行處理,經過後才更新到 $modelValue 上(若是驗證器管道沒經過,不會更新)。

核心管道

  1. $parsers 改變視圖值的格式,並更新的到模型($viewValue -> $modelValue),與之相對的是 $formatters,恰好反過來。

  2. $validators 用來添加同步驗證器

  3. $asyncValidators 用來添加異步驗證器

經常使用屬性

  1. $error 沒有經過的驗證器名稱及對應的錯誤信息

  2. $valid 表單項是否都經過驗證,都經過時爲 true,與之相對的是 $invalid

  3. $touched 表單項是否被訪問過,若是得到過焦點,在失去時該值爲 true,與之相對的是 $untouched

  4. $dirty 表示用戶是否和表單項交互過(好比輸入一些東西),只要有任何改變,該值爲 true,與之相對的是 $pristine

經常使用方法

  1. $render 定義視圖具體的渲染方式

  2. $setViewValue 設置視圖值(須要手動觸發一個 $digest),使用場景是在自定義指令中監聽自定義事件(好比使用具備回調的 jQuery 插件)

自定義同步驗證 & 異步驗證

ngModelController 中講到,AngularJS 1.3 提供了驗證器管道,同步驗證只須要加到 $validators 上便可。

好比,有這樣一個常見的需求,對一個必填的名稱表單項,要求只能輸入中英文,最小長度爲2位字符,那麼能夠這樣實現。

指令:

app.directive('nameCheck', nameCheck);

nameCheck.$inject = ['$http', '$q'];

function nameCheck($http, $q){
    var NAME_REG = /^[a-zA-Z\u4e00-\u9fa5]+$/;
    return {
        restrict: 'A',
        require: 'ngModel',
        link:function($scope,element,attrs,ctrl){
            // 同步驗證
            ctrl.$validators.char = function(modelValue, viewValue) {
                var value = modelValue || viewValue;
                if(!NAME_REG.test(value)){
                    return false;
                }
                return true;
            };
            // 異步驗證
            ctrl.$asyncValidators.exist = function(modelValue, viewValue){
                var value = modelValue || viewValue; 
                var deferred = $q.defer();
                $http.get('api/users/' + value).then(function(res) {
                    if(res.data.isExist){
                        deferred.reject(false);
                    }
                    deferred.resolve(true);
                })
                return deferred.promise;
            }
        }
    }
}

主頁面:

<form name="myForm">
    <div class="form-group">
        <input type="text" name="username" ng-model="username" class="form-control" name-check minlength="2" required>
        <span ng-messages="myForm.username.$error" ng-messages-include="error.html" ng-show="myForm.username.$touched">    
        </span>
    </div>
</form>

錯誤信息頁面:

<span ng-message="required">必填</span>
<span ng-message="char">非法字符</span>
<span ng-message="minlength">過短了</span>
<span ng-message="exist">名稱已存在</span>

ngMessages

ng-messages 是 AngularJS 1.3 提供的一個用來加強模版顯示的模塊,主要用在處理複雜的錯誤信息。

在之前的版本中,若是想處理錯誤信息的顯示,可能須要定義一堆 code 再結合複雜的 ng-if 語句來實現。並且在輸入同時知足多條錯誤規則的狀況下,沒法控制錯誤信息顯示的優先級。這些,使用 ng-messages 能夠完美解決。

準備工做

  1. 引入 angular-messages.js

  2. 添加依賴:angular.module('app', ['ngMessages'])

使用方法

有兩種使用方法,一是將 ng-messages 看成屬性指令使用:

<form name="myForm">
    <input type="text" ng-model="field" name="myField" required minlength="5" />
    <div ng-messages="myForm.myField.$error">
        <div ng-message="required">必填</div>
        <div ng-message="minlength">長度不夠</div>
    </div>
</form>

這樣會按照各個錯誤信息書寫的前後順序進行單一顯示,若是想同時顯示全部的錯誤信息,加個 ng-messages-multiple

<div ng-messages="myForm.myField.$error" ng-messages-multiple></div>

另外一種是將 ng-messages 看成元素指令使用:

<ng-messages for="myForm.myField.$error">
    <ng-message when="required">必填</ng-message>
    <ng-message when="minlength">長度不夠</ng-message>
</ng-messages>

若是不少表單項的錯誤提示信息都同樣,也能夠把錯誤信息放在模版裏,使用 ng-messages-include 指令來引用:

<div ng-messages="myForm.username.$error" ng-messages-include="validateTemplate/error.html">
</div>

錯誤模版文件:

<div ng-message="required">必填</div>
<div ng-message="minlength">長度不夠</div>

更詳細的使用辦法直接看 angular-messages.js 源文件裏面的註釋便可。

相關文章
相關標籤/搜索