其實我沒有那麼喜歡寫程式

Validation: The Angular Way(基礎)

最近學了一段時間的Angular,也開使用在現有的專案上,剛好有機會可以幫手邊負責的專案擴充一些Angular的驗證directive。不管是學哪個Library和FrameWork,其實驗證一直是我最不感興趣的東西,但最近在幫手邊的專案作用戶端驗證時,發現Angular的驗證真的非常的方便,擴充自己要的驗證directive也不會太難。

這篇文章會先介紹Agular基本的驗證機制,接下來才會進入如何擴充Angularjs驗證的directive。

首先我們先看個範例,有個表單我們希望使用者名稱和Email為必填,且Email必須符合正確的個式。

那Angular如何幫我們驗證呢? 這裡是這個表單的code

<form name="logOnForm" class="form-horizontal" novalidate>
    <input name="userName" type="text" class="form-control" ng-model="userName" required>
    <span ng-show="logOnForm.userName.$error.required">
        請輸入使用者名稱
    </span>
    <input name="email" type="email" class="form-control" id="email" placeholder="Email" ng-model="email" required>
    <span ng-show="logOnForm.email.$error.required">
        請輸入Email
    </span>
</form>

預設能使用的驗證

這裡我沒有寫認何一行javascript的code就做好了基本的用戶端驗證
希望欄位是必填欄位,我只需要在表單欄位加上Html5標準的required屬性,angular就會幫我們驗證該欄位是否合法。那angular提供了哪些基本的驗證呢?

必填

驗證使用者是否輸入值,只要加上簡單的Html5 Attribute required就能夠使用

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

最小長度

驗證使用者輸入的文字是否符合最小長度,我們只要加上ng-minlength這個directive

<input type="text" ng-model="name" ng-minlength="3">

最大長度

驗證使用者輸入的文字是否符合最大長度,我們只要加上ng-axlength這個directive

<input type="text" ng-model="name" ng-maxlength="12">

正規表達式

所有angular提供的基本驗證中最有趣的。 我們可以設定正規表達式來進行驗證,使用directive:ng-pattern="/pattern/"

<input type="text" ng-model="name" ng-pattern="/[0-9]/">

數字

必須為數字欄位,只需將type設為number

<input type="number" ng-model="age">

Email

必須為正確的Email,只需將type設為email

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

Url

必須為正確的Url,只需將type設為url

<input type="url" ng-model="url">

表單欄位狀態

那我們要如何知道欄位發生錯誤和定義錯誤訊息呢?
我們可以透過以下的格式取得驗證是否通過
formName.inputFieldName.$error.errorType

例如用logOnForm.userName.$error.required可以取得下面表單的userName欄位是否通過required驗證,若驗證不過則會取得true,通過則取得false

<form name="logOnForm" class="form-horizontal" novalidate role="form" ng-controller="demo1Ctrl">
    <input name="userName" type="text" class="form-control" ng-model="userName" required>
</form>

我們能利用該屬性定義錯誤訊息,若logOnForm.userName.$error.required為true則顯示,若為false則隱藏

<form name="logOnForm" class="form-horizontal" novalidate>
    <input name="userName" type="text" class="form-control" ng-model="userName" required>
    <span ng-show="logOnForm.userName.$error.required">請輸入使用者名稱</span>
</form>
取得其他驗證狀態

formName.inputFieldName.$error.required
formName.inputFieldName.$error.email
formName.inputFieldName.$error.url
formName.inputFieldName.$error.maxlength
formName.inputFieldName.$error.minlength
formName.inputFieldName.$error.pattern

除了$error我們還可以取得其他有用的屬性

$valid

取得該欄位是否通過驗證,若無任何驗證失敗則回傳true,否則回傳false

formName.inputFieldName.$valid;

$invalid

和$valid相反

formName.inputFieldName.$valid;

$pristine

若該input欄位還沒有輸入過值,則為true,否則為false

formName.inputFieldName.$pristine;

$dirty

若該input欄位以經輸入過值,則為true,否則為false

formName.inputFieldName.$dirty;

若我們不希望使用者還沒輸入過表單就出現錯誤訊息,可以用以下技巧

<form name="logOnForm" class="form-horizontal" novalidate>
    <input name="userName" type="text" class="form-control" ng-model="userName" required>
    <span ng-show="logOnForm.userName.$error.required && logOnForm.userName.$dirty">
        請輸入使用者名稱
    </span>
</form>

以上這些屬性form也可以取得
例如 formName.$invalid
所以我們可以利用以下技巧防止使用者送出未通過驗證的表單

<form name="logOnForm" class="form-horizontal" novalidate ng-submit="logOn()">
    <input name="userName" type="text" class="form-control" ng-model="userName" required>
    <span ng-show="logOnForm.userName.$error.required && logOnForm.userName.$dirty">
        請輸入使用者名稱
    </span>
    <input type="submit" ng-disabled="logOnForm.$invalid" />
</form>

或者在Controller裡定義submit事件的方法裡檢查

function formController($scope) {
    $scope.logOn = function(){
        if($scope.logOnForm.$invalid) return;
        //省略
    };
}

為表單欄位設計樣式

AngularJs在處理表單的狀態時,會為表單加入各種狀態的class,每個屬性都有對應的class,我們可以根據這些class定義各種狀態的CSS樣式。
ng-pristine
ng-dirty
ng-valid
ng-invalid
ng-valid-errorType
ng-invalid-errorType

我們可以利用這些class來幫我們的表單增加一些色彩

css
input.ng-invalid{
   background-color:  #fcf8e3;
   border-color: red;
}

input.ng-valid{
   border-color: green;
}

html
<form name="logOnForm" class="form-horizontal" novalidate ng-submit="logOn()">
    <input name="userName" type="text" class="form-control" ng-model="userName" required>
    <span ng-show="logOnForm.userName.$error.required && logOnForm.userName.$dirty">
        請輸入使用者名稱
    </span>
    <input type="submit" ng-disabled="logOnForm.$invalid" />
</form>

Agularjs的驗證真的非常簡單好用,但光會這些很難應付複雜的應用程式,接下來我會介紹如何建立自己的驗證directive和一些我認為好用的小技巧。