歡迎轉載(註明出處)或直接轉貼網址也ok,但是請不要直接把內容摳走貼在別的地方~

前言 :  

這篇寫超久的,大概超過三個禮拜了吧,有點忙啊!

學了那麼久的 AngularJS (學得很慢) 終於學到感覺比較有趣的表單驗證啦!

所以這一篇主要是要來紀錄學習心得 + 如何在網頁表單中使用 AngularJS 來做資料驗證

驗證的話,AngularJS 搭配 HTML5 的一些屬性就可以做到很強大的表單驗證與提示了

目前大部分使用者的瀏覽器幾乎都可接受 HTML5 了,ie9 以下的瀏覽器應該也很難找到

所以使用 HTML5 做驗證應該不是太大的問題

在開始 angularjs 驗證之前先來熟悉一下 HTML5簡單的驗證方式,因為比較簡單

而 angularjs 必須要搭配HTML5 還有formController 的表單狀態屬性和 $error 物件來處理

底下為這篇稍微分類一下 

1. HTML5 表單驗證

2. AngularJS 表單驗證

2.1. FormController 的 Properties 介紹

2.2. 表單驗證的簡單範例

3. AngularJS 表單的狀態樣式 

3.1. 表單狀態樣式的應用範例

4. 使用 ng-form 的巢狀表單

5. 在 Controller 中檢查表單驗證結果

6. 使用 ASP.Net 傳統 Web Form 開發所遇到的問題 

 

1. HTML5 表單驗證

required

表單送出時會自動檢查該欄位是否有輸入值 (空值也是值),沒輸入值就會像下圖一樣跳出訊息

required   

用法就像下面這樣,用一個屬性取代幾行 javascript 判斷還蠻划算的

 

placeholder

用來顯示提示文字用 ex : <input type="text" placeholder="請輸入電子郵件" />

上面是使用 placeholder 的文字輸入,下面則是一般的 textbox

擷取   

 

<input type="email" />

表單送出時會檢查欄位值是否為正確的 email 格式

ex : <input type="email" />

email   

 

minlength、maxlength

ex : <input type="text" minlength="3" maxlength="6" />

限制文字輸入的字元數,最多只能輸入6個字,若不足3碼,送出時會跳出提示

minlength  

 

<input type="number" />、max、min

輸入格式為數字,然後可以用 max、min 來規範數字的範圍

ex : <input type="number" max="9" min="5" />

Clipboard02   

 

<input type="url" />

表單送出時會檢查輸入的值是否為正確的 url 格式

ex : <input type="url" />

url   

 

pattern

使用規則表示式來驗證

ex : <input type="text" pattern="[A-Za-z0-9]" />

以上例而言就是輸入必須要為A ~ Z、a ~ z、0 ~ 9,不允許特殊符號

reg   

 

以上是一些HTML5內建的簡單驗證,還有很多好用的表單控制請自行參考

HTML5 forms : http://www.w3.org/TR/html5/forms.html#forms

因為 AngularJS 的部分驗證是必需要搭配 HTML5的,所以稍微了解之後就來進入重頭戲

 

2. AngularJS 表單驗證 - FormController 的 Properties 

接下來才是這篇要學習的重點,使用 AngularJS 來做驗證

當使用 AngularJS 來做表單驗證的時候,AngularJS 會建立一個 FormController 來保存表單目前的狀態

並且提供一些方法可以使用,有關於 FormController 可以參考官方文件

https://docs.angularjs.org/api/ng/type/form.FormController

文件中的方法(method)現在還不知道要怎麼使用......還沒學到,這次要看的是屬性 Properties

以下列出 FromController 中的所有屬性 (官網的資料)

Properties

  • $pristine

    boolean

    True if user has not interacted with the form yet.

  • $dirty

    boolean

    True if user has already interacted with the form.

  • $valid

    boolean

    True if all of the containing forms and controls are valid.

  • $invalid

    boolean

    True if at least one containing control or form is invalid.

  • $submitted

    boolean

    True if user has submitted the form even if its invalid.

  • $error

    Object

    Is an object hash, containing references to controls or forms with failing validators, where:

    • keys are validation tokens (error names),
    • values are arrays of controls or forms that have a failing validator for given error name.

      Built-in validation tokens:

    • email

    • max
    • maxlength
    • min
    • minlength
    • number
    • pattern
    • required
    • url
    • date
    • datetimelocal
    • time
    • week
    • month

上面的 $submitted 是 1.3 版本才有的,每一個都跟表單的狀態有關

然後 $error 稍微比較特別一些,所以首先先來看看 $error 

 

$error

透過上面的列表可以發現,除了最後一個 $error 是物件之外,其他都是 boolean (ture or false)

使用這些屬性的方法很簡單,就是透過 formName.inputFieldName.Properies

用例子來看最清楚了

ex : 

<form name="form1" ng-app="">
<input type="text"
name="account"
ng-model="userAccount"
ng-minlength="3"
ng-maxlength="5"
autocomplete="off"
required
/><br />
{{ form1.account.$error }}
</form>

如上面的範例使用 form1.account.$error 取得Properies 裡的 $error 物件

就是透過抓取 form 的名字為 form1,textbox 的名字為 account,然後抓到該屬性的

$error 物件顧名思義就是一個有關錯誤的物件,把抓取到的 $error 物件呈現出來看就會長這樣

{"required":true,"maxlength":false,"minlength":false}

裡面的那些參數都是我們設定過的 ng-minlength、ng-maxlength、required,而狀態被 FormController 所記錄下來

可以自行切換到 result 看看變化的結果 

所以之後如果要檢查驗證結果就可以直接用下面這方法了

ex : form1.account.$error.required ,就會返回 ture or false 

如下面的例子 

如官網的文件所寫的,在 $error 物件中可檢查的項目有以下這些,必須要搭配 HTML5來做驗證

也就是說如果要檢查 email,那就是要用 <input type="email" />

想檢查 url 就是要用 <input type="url" />

  • email
  • max
  • maxlength
  • min
  • minlength
  • number
  • pattern
  • required
  • url
  • date
  • datetimelocal
  • time
  • week
  • month

等等再來挑幾個練習一下,先來看看 $error 之外的 Properties 

 

$pristine

如果該欄位還沒輸入過值,就會返回 true 反之為 false

使用方式也是一樣 : formName.inputFieldName.$pristine

 

$dirty

若該欄位之前曾經輸入過值就會返回 true (因為用過髒掉了嘛) 反之則是 false

 

$valid

如果該欄位有通過驗證的話就會返回 true 反之 false

 

$invalid

若該欄位沒有通過驗證的話就會返回 true 反之 false

 

$submitted (1.3 新增)

如果表單曾經送出過,不論有沒有通過驗證都會返回 true

 

2.2 簡單範例

以下就來稍微練習一下如何應用上面的表單屬性吧

 

練習一、Email 驗證

上面說過 AngularJS 的驗證是要結合 HTML5 的,所以驗證 email 就用了 <input type="email" />

然後結合 ng-class,當發生錯誤就套用 .msg  的樣式,也可以直接用 ng-show 來做顯示與隱藏

HTML

<form name="form1" ng-app="">
<input type="email" name="email" ng-model="email" placeholder="請輸入email" />
<span
ng-class="{'alert':form1.email.$error.email}"
ng-show="form1.email.$error.email">
email格式錯誤
</span>
</form>

CSS

.alert{
color:red;
display:inline;

結果如下 : 

 

練習二、ng-minlength、ng-maxlength、ng-pattern 的檢查

下面這個也是自己隨便練習的範例,用來練習帳號長度檢查 + 密碼規則驗證

最後在 submit 按鈕上面綁 ng-disabled,當表單驗證沒通過的話就會回傳 ture 讓按鈕 disabled 

ng-pattern 則是用來驗證規則表示式,一樣是 pattern ,在HTML5中則不須輸入開始與結束符號 "/"

如下 :

<form name="form1" ng-app="">
帳號:
<input type="text"
name="account"
ng-model="userAccount"
ng-minlength="3"
ng-maxlength="8"
placeholder="帳號長度 3 ~ 8"
autocomplete="off"
required
/><br /><br />
HTML5 密碼:
<input type="text"
name="pass"
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,10}$"
placeholder="至少一個大寫字母 + 一個小寫字母 + 一個數字,且長度 6 ~ 10"
size="50"
required
/>
<br /><br />
AngularJS 密碼:
<input type="text"
name="pass2"
ng-model="pass2"
ng-pattern="/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,10}$/"
placeholder="至少一個大寫字母 + 一個小寫字母 + 一個數字,且長度 6 ~ 10"
size="50"
required
/>
<alert ng-class="{'error':form1.pass2.$error.pattern}">
密碼不符合規範
</alert>
<br /><br />
<input type="submit" value="send" ng-disabled="form1.$invalid" />
</form>

實際結果 : 

再繼續生出其他例子來練習之前,先來稍微停一下.....

以上範例的提示訊息不外乎是HTML5內建、或是搭配使用 ng-class 針對表單狀態而呈現的

例如當密碼輸入規則不符合驗證條件時,就會搭配 ng-class 或是 ng-show 來顯示錯誤訊息

但其實 AngularJS 也有內建表單狀態的樣式,下面先來學一下怎麼使用~

 

3. AngularJS 表單狀態樣式

上面有提到表單的驗證中有各種狀態 ex: $valid、$invalid 、$dirty、$pristine.....等

如剛剛上面的範例所示,我們可以使用 ng-class 搭配上面這些表單狀態呈現出不同的提示效果提醒使用者 

ex: 未填寫資料,或是與驗證格式不符的話,就將 textbox 變成紅框之類的

但其實除了使用 ng-class 之外,AngularJS 有提供相關狀態的 CSS 來方便使用

可以參考官網這個連結 : https://docs.angularjs.org/api/ng/directive/form

CSS classes

  • ng-valid is set if the form is valid.
  • ng-invalid is set if the form is invalid.
  • ng-pristine is set if the form is pristine.
  • ng-dirty is set if the form is dirty.
  • ng-submitted is set if the form was submitted.

直接來看個簡單的例子好了

HTML :

<form name="form1" ng-app="">
帳號:
<input type="text"
name="account"
ng-model="userAccount"
ng-minlength="3"
ng-maxlength="8"
placeholder="帳號長度 3 ~ 8"
autocomplete="off"
/>
</form>

CSS :

input.ng-invalid {
border: 1px solid red;
background: red;
padding: 5px;
}

原本的 CSS Selector 後面直接接上 .ng-invalid 之類的狀態 class name 即可

效果如下 :

除了上面用的 .ng-invalid 還有下面這些,基本上是每個狀態都有一個相對應的 class name

 輸入狀態  CSS 類別名稱
$invalid ng-invalid
$valid  ng-valid 
$pristine  ng-pristine 
$dirty  ng-dirty 
$submitted ng-submitted
required  ng-valid-required  或 ng-invalid-required
min  ng-valid-min 或 ng-invalid-min 
max  ng-valid-max 或 ng-invalid-max  
minlength  ng-valid-minlength 或 ng-invalid-minlength
maxlength  ng-valid-maxlength 或 ng-invalid-maxlength 
pattern  ng-valid-pattern 或 ng-invalid-pattern
url  ng-valid-url 或 ng-invalid-url 
email  ng-valid-email 或 ng-invalid-email 
date  ng-valid-date 或 ng-invalid-date 
number  ng-valid-number 或 ng-invalid-number 

 

再來下面用實際的例子來看看怎麼應用

練習一、Email 驗證提醒

這也是一個簡單的範例,主要是利用上面講的狀態 CSS 來簡單做到提示使用者的功能

HTML

<form name="form1" ng-app="">
email:
<input type="email"
name="email"
ng-model="email"
placeholder="請輸入email"
autocomplete="off"
required
/>
<input type="submit" value="送出" />
</form>

CSS: 

/* 把 input 弄得漂亮一點 */
input {
padding: 8px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
/* 把 input 預設的click外框拿掉 */
input:focus {
outline: 0;
}
/* 如果驗證未通過,呈現紅框 */
input.ng-invalid {
border:1px solid red;
}
/* 如果驗證通過,呈現綠框 */
input.ng-valid {
border:1px solid green;
}
/* 如果已經被輸入過且驗證失敗,加入粉紅色背景 */
input.ng-dirty.ng-invalid {
background: #ffecec;
}

上面的範例的 HTML 基本上沒什麼特別的,主要就是必須要輸入 email 格式,主要的提示效果在 CSS 裡

這範例想要做到的效果是....

1. 因為是必填欄位,所以在尚未輸入的時候要是紅框,提醒使用者必填

套用的是這個 CSS: input.ng-invalid  (代表input 驗證未通過)

擷取  

2. 當使用者輸入之後就會檢查是否為正確的 email 格式,如果不是正確的 email 格式,就將背景上色

套用的是這個 CSS: input.ng-dirty.ng-invalid (代表已經輸入過,但是驗證失敗)

擷取  

3. 如果輸入的 email 是正確的格式就會呈現綠框 ,代表通過驗證

套用的是這個 CSS:input.ng-valid  (通過驗證)

擷取  

實際的結果如下 : 

 

4. 使用 ng-form 的巢狀表單

所謂的巢狀表單指的就是類似這樣的感覺....(當然一個正確的HTML不可能有巢狀 <form>)

<form name="formMain">
<form name="formA">
.........
<span ng-show="formA.$invalid">formA error</span>
</form>
<form name="formB">
...........
<span ng-show="formB.$invalid">formB error</span>
</form>
</form>

就是一個表單內有多個表單群組,就可以針對各群組來進行各別的表單檢查

就像上面範例的檢查方式,可以檢查子表單 formA 與 formB

但是以上的 HTML 是不正確的,因為 HTML 沒有巢狀 form 這東西

所以 AngularJs 提供了 ng-form 來模擬表單

所以上面就可以寫成這樣

<form name="formMain">
<ng-form name="formA">
.........
<span ng-show="formA.$invalid">formA error</span>
</ng-form>
<ng-form name="formB">
...........
<span ng-show="formB.$invalid">formB error</span>
</ng-form>
</form>

這邊有幾個要注意的地方是 : 

子表單的狀態可以直接存取 ex : formA.$invalid

也可以由父表單開始存取 ex : formMain.formA.$invalid 兩種方式都 ok 喔

但是子表單也會影響到父表單,例如子表單如果設定了 required 但是卻沒填資料

那父表單 formMain.$invalid 還是會等於 true (驗證失敗的意思)

 

在 Controller 中檢查表單驗證結果

前面的例子都是在按下送出按鈕前,利用 CSS 來做到提示使用者表單資料是否正確

那如果想要按下按鈕之後在 controller 之中檢查驗證結果,然後做一些事情呢?

方法好像很多種,有些還沒學到....不過先參考參考~

像下面這個

AngularJs can't access form object in controller ($scope) 

另一種方法 :

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="myapp" ng-controller="mycontroller as ctrl">
<form name="ctrl.myForm">
Dirty? {{ ctrl.myForm.$dirty }}
<button ng-click="ctrl.saveChanges()">Save</button>
</form>
</div>
<script>
angular.module("myapp", [])
.controller("mycontroller", [ function () {
var vm= this;
vm.saveChanges = function () {
alert(vm.myForm.$valid);
}
}]);
</script>

 

又另一種方法,但需要傳入 form name + event

<body ng-app="myapp" ng-controller="mycontroller as ctrl">
<form id="form1" runat="server" ng-submit="ctrl.check($event,form1)">
<ng-form name="form1">
<input type="text"
name="account"
ng-model="userAccount"
required
/>
<br />
<input type="submit" value="send" />
</ng-form>
</form>
<script>
angular.module("myapp", []).controller("mycontroller", ["$scope", function () {
var self = this;
self.check = function ($event,form1) {
if (form1.$valid) {
// 通過驗證
} else {
// 未通過驗證
}
// 取消 submit 原本預設的送出動作
$event.preventDefault();
}
}]);
</script>
</body>

  

使用 ASP.Net 傳統 Web Form 開發所遇到的問題

因為我的工作幾乎都是在寫傳統的 Web Form,所以這可以說是我的疑問

後來我去上課後得到了解答,請看這篇 "傳統的 ASP.Net Web Form 適合使用 AngularJS 來開發嗎?"

雖然如此還是來掙扎一下看看硬寫會出什麼事

如果你不是 ASP.Net  傳統 web form 的開發者的話可以跳過這段了

AngularJs 十分適合 ASP.Net MVC 來使用,但是非常不適合用在傳統的 Web Form 開發上

這是因為傳統的 Web Form 需要 postback,頁面一 postback, js 就不見啦

但如果你還是想要硬寫在傳統 web form 的話,就來看看以下可能會遇到的問題

第一個問題是,傳統 Web Form 所產生的網頁 form 是沒有 name 屬性的啊!

你就算像下面這樣硬寫也沒用~

擷取       

 編譯完之後就會自動幫你砍掉

擷取   

為何會這樣咧! 原因如下面這個連結所講的 

https://msdn.microsoft.com/zh-tw/library/exc57y7e(v=vs.100).aspx

exc57y7e.alert_note(zh-tw,VS.100).gif注意事項:

form 項目上的 name 屬性在 XHTML 1.1 方針中不允許使用。您可以將應用程式設定為不呈現 name 屬性。如需詳細資訊,請參閱本主題稍後的「控制 ASP.NET 網頁和控制項的呈現」。

原因就是ASP.Net 為了全面符合 XHTML 1.1,而 XHTML 1.1 的規範裡面 form 是沒有 name 屬性的

不過你可以使用下面這個連結來改變這個很煩的設定

HOW TO:在 ASP.NET 網站中設定 XHTML 呈現

但是要注意更改了 web.config 之後,ASP.NET 網頁和控制項會將其呈現變更為 ASP.NET 先前版本的行為

包含下面這些.....

  1. form 項目會使用 name 屬性呈現。
  2. ASP.NET 不會自動將 form 項目中的 div 項目呈現為控制項的容器。
  3. 會使用自訂屬性將驗證程式控制項呈現為 span 項目,例如 controltovalidate。
  4. 除非您明確包含這些屬性,否則 img 項目不會呈現 alt 和 src 屬性。
  5. 如果需要支援自動回傳行為,控制項會呈現 language 屬性 (例如 language="javascript")。
  6. 如果控制項的 Wrap 屬性設定為 false,nowrap 屬性會包含在呈現 div 項目的控制項中 (例如 Panel 控制項)。
  7. ImageButton 控制項呈現 border 屬性。
  8. 呈現至網頁的任何 br 項目都會呈現為 <br>。然而,如果您明確包含 <br /> 標記,網頁就會依原本的方式呈現它。
  9. DataGrid 和 Calendar 控制項會將 bordercolor 屬性包含在呈現的 table 項目中 (如果其設定 BackColor 屬性)。

但看到改設定變動這麼大還是不要動的好

這個問題會造成你在做表單檢查的時候無法用 form name 來控制表單狀態

解決方式就是可以使用上面提到的 ng-form 來建立虛擬的 form 

第二個遇到的問題就是 ASP.Net 傳統的 Web Form 是需要 submit 後 action 到自己的

按下 submit 之後若沒擋住你前面的 js 就會不見了,所以就勢必要在 <form> 裡面加上 ng-submit 事件

然後在 controller 中用 return false or preventDefault 取消 submit 預設的送出動作

如同這個例子 : 

<body ng-app="myapp" ng-controller="mycontroller as ctrl">
<form id="form1" runat="server" ng-submit="ctrl.check($event,form1)">
<ng-form name="form1">
<input type="text"
name="account"
ng-model="userAccount"
required
/>
<br />
<input type="submit" value="send" />
</ng-form>
</form>
<script>
angular.module("myapp", []).controller("mycontroller", ["$scope", function () {
var self = this;
self.check = function ($event,form1) {
if (form1.$valid) {
// 通過驗證
} else {
// 未通過驗證
}
// 取消 submit 原本預設的送出動作
$event.preventDefault();
}
}]);
</script>
</body>

禁止表單送出之後,再利用 AJAX 來做到 CRUD 的效果

但最後的建議還是不要太自虐

ASP.Net 傳統的 Web Form 不要使用 AngularJs 開發比較好

 

 

AngularJS 學習筆記系列 : (依本人的上進心持續增加)

AngularJS 初學者筆記與教學 (一) - 使用方式、Expression、Controller、Module

AngularJS 初學者筆記與教學 (二) 內建的簡單指令之1 ng-click、ng-show、ng-hide

AngularJS 初學者筆記與教學 (三) - AngularJS 的載入流程與 ng-cloak 運作原理 

AngularJS 初學者筆記與教學 (四) - 如何動態改變 CSS 樣式,使用 ng-class、ng-style

AngularJS 初學者筆記與教學 (五) - 繼續深入學習常用的 ng-repeat

AngularJS 初學者筆記與教學 (六) - 單元測試

AngularJS 初學者筆記與教學 (新手入門課程 - 課後心得篇)

AngularJS 初學者筆記與教學 (七) - FormController 的表單驗證與資料檢查

 

創作者介紹
創作者 小雕 的頭像
小雕

小雕雕的家

小雕 發表在 痞客邦 留言(1) 人氣()


留言列表 (1)

發表留言
  • 悄悄話