過濾器用來格式化需要展示給用戶的數(shù)據(jù)扇丛。AngularJS有很多實(shí)用的內(nèi)置過濾器,同時(shí)也提供了方便的途徑可以自己創(chuàng)建過濾器落午。
??在HTML中的模板綁定符號{{ }}
內(nèi)通過 | 符號來調(diào)用過濾器饺窿。如果要同時(shí)使用多個(gè)過濾器,可以用 | 符號作為分割符來使用多個(gè)過濾器缺脉。例如,假設(shè)我們希望將字符串轉(zhuǎn)換成大寫悦穿,可以對字符串中的每個(gè)字符都單獨(dú)進(jìn)行轉(zhuǎn)換操作攻礼,也可以使用過濾器:{{ name | uppercase }}
。
??在JavaScript代碼中可以通過$filter
來調(diào)用過濾器栗柒。例如礁扮,在JavaScript代碼中使用lowercase
過濾器:
app.controller('DemoController', ['$scope', '$filter',
function($scope, $filter) {
$scope.name = $filter('lowercase')('Ari');
}]);
以HTML的形式使用過濾器時(shí)知举,如果需要傳遞參數(shù)給過濾器,只要在過濾器名字后面加冒號即可太伊。如果有多個(gè)參數(shù)雇锡,可以在每個(gè)參數(shù)后面都加入冒號。例如僚焦,數(shù)值過濾器可以限制小數(shù)點(diǎn)后的位數(shù)锰提,在過濾器后寫上 :2 可以將2作為參數(shù)傳給過濾器:
<!-- 顯示:123.46 -->
{{ 123.456789 | number:2 }}
內(nèi)置過濾器
currency
currecy過濾器可以將一個(gè)數(shù)值格式化為貨幣格式。
{{ 123456 | currency }} <!--$123,456.00-->
currecy過濾器允許我們自己設(shè)置貨幣符號芳悲。默認(rèn)情況下會采用客戶端所處區(qū)域的貨幣符號立肘,但是也可以自定義貨幣符號。給currency
傳遞一個(gè)字符串類型的參數(shù)名扛,就可以自定義貨幣符號了谅年。
{{ 123456 | currency:'¥' }} <!-- ¥123,456.00-->
date
date過濾器可以將日期格式化成需要的格式。AngularJS中內(nèi)置了幾種日期格式肮韧,如果沒有指定使用任何格式融蹂,默認(rèn)會采用mediumDate
格式。
下面是內(nèi)置的支持本地化的日期格式:
{{ today | date:'medium' }} <!-- Dec 14, 2016 5:29:38 PM -->
{{ today | date:'short' }} <!-- 12/14/16 5:30 PM -->
{{ today | date:'fullDate' }} <!-- Wednesday, December 14, 2016 -->
{{ today | date:'longDate' }} <!-- December 14, 2016 -->
{{ today | date:'mediumDate' }} <!-- Dec 14, 2016 -->
{{ today | date:'shortDate' }} <!-- 12/14/16 -->
{{ today | date:'mediumTime' }} <!-- 5:33:19 PM -->
{{ today | date:'shortTime' }} <!-- 5:33 PM -->
// 年份格式化
四位年份:{{ today | date:'yyyy' }} <!-- 2016 -->
兩位年份:{{ today | date:'yy' }} <!-- 16 -->
一位年份:{{ today | date:'y' }} <!-- 2016 -->
// 月份格式化
英文月份:{{ today | date:'MMMM' }} <!-- August -->
英文月份簡寫:{{ today | date:'MMM' }} <!-- Aug -->
數(shù)字月份:{{ today |date:'MM' }} <!-- 08 -->
一年中的第幾個(gè)月份:{{ today |date:'M' }} <!-- 8 -->
// 日期格式化
數(shù)字日期:{{ today|date:'dd' }} <!-- 09 -->
一個(gè)月中的第幾天:{{ today | date:'d' }} <!-- 9 -->
英文星期:{{ today | date:'EEEE' }} <!-- Thursday -->
英文星期簡寫:{{ today | date:'EEE' }} <!-- Thu -->
// 小時(shí)格式化
24小時(shí)制數(shù)字小時(shí):{{today|date:'HH'}} <!--00-->
一天中的第幾個(gè)小時(shí):{{today|date:'H'}} <!--0-->
12小時(shí)制數(shù)字小時(shí):{{today|date:'hh'}} <!--12-->
上午或下午的第幾個(gè)小時(shí):{{today|date:'h'}} <!--12-->
// 分鐘格式化
數(shù)字分鐘數(shù):{{ today | date:'mm' }} <!-- 09 -->
一個(gè)小時(shí)中的第幾分鐘:{{ today | date:'m' }} <!-- 9 -->
// 秒數(shù)格式化
數(shù)字秒數(shù):{{ today | date:'ss' }} <!-- 02 -->
一分鐘內(nèi)的第幾秒:{{ today | date:'s' }} <!-- 2 -->
毫秒數(shù):{{ today | date:'.sss' } } <!-- .995 -->
// 字符格式化
上下午標(biāo)識:{{ today | date:'a' }} <!-- AM -->
四位時(shí)區(qū)標(biāo)識:{{ today | date:'Z' }} <!--- 0700 -->
// 一些自定義日期格式:
{{ today | date:'MMMd, y' }} <!-- Dec14,2016 -->
{{ today | date:'EEEE, d, M' }} <!-- Wednesday, 14, 12 -->
{{ today | date:'hh:mm:ss.sss' }} <!-- 05:38:32.673 -->
filter
filter過濾器可以從給定數(shù)組中選擇一個(gè)子集弄企,并將其生成一個(gè)新數(shù)組返回殿较。這個(gè)過濾器通常用來過濾需要進(jìn)行展示的元素。
??這個(gè)過濾器的第一個(gè)參數(shù)可以是字符串桩蓉、對象或是一個(gè)用來從數(shù)組中選擇元素的函數(shù)淋纲。下面分情況介紹傳入不同類型的參數(shù)。
- 字符串
返回所有包含這個(gè)字符串的元素院究。如果我們想返回不包含該字符串的元素洽瞬,在參數(shù)前加 ! 符號。 - 對象
AngularJS會將待過濾對象的屬性同這個(gè)對象中的同名屬性進(jìn)行比較业汰,如果屬性值是字符串就會判斷是否包含該字符串伙窃。如果我們希望對全部屬性都進(jìn)行對比,可以將 $ 當(dāng)作鍵名样漆。 - 函數(shù)
對每個(gè)元素都執(zhí)行這個(gè)函數(shù)为障,返回非假值的元素會出現(xiàn)在新的數(shù)組中并返回。
例如放祟,用下面的過濾器可以選擇所有包含字母e的單詞:
{{ ['Ari','Lerner','Likes','To','Eat','Pizza'] | filter:'e' }}
<!-- ["Lerner","Likes","Eat"] -->
如果要過濾對象鳍怨,可以使用對象過濾器。例如跪妥,如果有一個(gè)由people對象組成的數(shù)組鞋喇,每個(gè)對象都含有他們最喜歡吃的食物的列表,那么可以用下面的形式進(jìn)行過濾:
{{ [{
'name': 'Ari',
'City': 'San Francisco',
'favorite food': 'Pizza'
},{
'name': 'Nate',
'City': 'San Francisco',
'favorite food': 'indian food'
}] | filter:{'favorite food': 'Pizza'} }}
<!-- [{"name":"Ari","City":"SanFrancisco","favoritefood":"Pizza"}] -->
也可以用自定義函數(shù)進(jìn)行過濾:
{{ ['Ari','likes','to','travel'] | filter:isCapitalized }}
<!-- ["Ari"] -->
isCapitalized
函數(shù)的功能是根據(jù)首字母是否為大寫返回 true 或 false眉撵,具體如下所示:
$scope.isCapitalized = function(str) {
return str[0] == str[0].toUpperCase();
};
我們也可以給filter過濾器傳入第二個(gè)參數(shù)侦香,用來指定預(yù)期值同實(shí)際值進(jìn)行比較的方式落塑。
??第二個(gè)參數(shù)可以是以下三種情況之一。
- true
用angular.equals(expected, actual)
對兩個(gè)值進(jìn)行嚴(yán)格比較罐韩。 - false
進(jìn)行區(qū)分大小寫的子字符串比較憾赁。 - 函數(shù)
運(yùn)行這個(gè)函數(shù),如果返回真值就接受這個(gè)元素散吵。
json
json過濾器可以將一個(gè)JSON或JavaScript對象轉(zhuǎn)換成字符串缠沈。這種轉(zhuǎn)換對調(diào)試非常有幫助:
{{ {'name': 'Ari', 'City': 'SanFrancisco'} | json }}
<!-- { "name": "Ari", "City": "San Francisco" } -->
limitTo
limitTo
過濾器會根據(jù)傳入的參數(shù)生成一個(gè)新的數(shù)組或字符串,新的數(shù)組或字符串的長度取決于傳入的參數(shù)错蝴,通過傳入?yún)?shù)的正負(fù)值來控制從前面還是從后面開始截取。如果傳入的長度值大于被操作數(shù)組或字符串的長度颓芭,那么整個(gè)數(shù)組或字符串都會被返回顷锰。
例如,我們可以截取字符串的前三個(gè)字符:
{{ 'San Francisco is very cloudy' | limitTo:3 }}
<!-- San -->
或最后的六個(gè)字符:
{{ 'San Francisco is very cloudy' | limitTo:-6 }}
<!-- cloudy -->
對數(shù)組也可以進(jìn)行同樣的操作亡问。返回?cái)?shù)組的第一個(gè)元素:
{{ ['a','b','c','d','e','f'] | limitTo:1 }}
<!-- ["a"] -->
lowercase
lowercase過濾器將字符串轉(zhuǎn)為小寫官紫。
{{ "San Francisco is very cloudy" | lowercase }}
<!-- san francisco is very cloudy -->
number
number過濾器將數(shù)字格式化成文本。它的第二個(gè)參數(shù)是可選的州藕,用來控制小數(shù)點(diǎn)后截取的位數(shù)束世。如果傳入了一個(gè)非數(shù)字字符,會返會空字符串床玻。
{{ 123456789 | number }}
<!-- 123,456,789 -->
{{ 1.234567 | number:2 }}
<!-- 1.23 -->
orderBy
orderBy過濾器可以用表達(dá)式對指定的數(shù)組進(jìn)行排序毁涉。
??orderBy可以接受兩個(gè)參數(shù),第一個(gè)是必需的锈死,第二個(gè)是可選的贫堰。
??第一個(gè)參數(shù)是用來確定數(shù)組排序方向的謂詞。
??下面分情況討論第一個(gè)參數(shù)的類型待牵。
- 函數(shù)
當(dāng)?shù)谝粋€(gè)參數(shù)是函數(shù)時(shí)其屏,該函數(shù)會被當(dāng)作待排序?qū)ο蟮?code>getter方法。 - 字符串
對這個(gè)字符串進(jìn)行解析的結(jié)果將決定數(shù)組元素的排序方向缨该。我們可以傳入 + 或 - 來強(qiáng)制進(jìn)行升序或降序排列偎行。 - 數(shù)組
在排序表達(dá)式中使用數(shù)組元素作為謂詞。對于與表達(dá)式結(jié)果并不嚴(yán)格相等的每個(gè)元素贰拿,則使用第一個(gè)謂詞蛤袒。
第二個(gè)參數(shù)用來控制排序的方向(是否逆向)。
例如膨更,我們將下面的對象數(shù)組用name字段進(jìn)行排序:
{{ [{
'name': 'Ari',
'status': 'awake'
},{
'name': 'Q',
'status': 'sleeping'
},{
'name': 'Nate',
'status': 'awake'
}] | orderBy:'name' }}
<!--
[
{"name":"Ari","status":"awake"},
{"name":"Nate","status":"awake"},
{"name":"Q","status":"sleeping"}
]
-->
也可以對排序結(jié)果進(jìn)行反轉(zhuǎn)汗盘。例如,通過將第二個(gè)參數(shù)設(shè)置為true可以將排序結(jié)果進(jìn)行反轉(zhuǎn):
{{ [{
'name': 'Ari',
'status': 'awake'
},{
'name': 'Q',
'status': 'sleeping'
},{
'name': 'Nate',
'status': 'awake'
}] | orderBy:'name':true }}
<!--
[
{"name":"Q","status":"sleeping"},
{"name":"Nate","status":"awake"},
{"name":"Ari","status":"awake"}
]
-->
uppercase
uppercase過濾器可以將字符串轉(zhuǎn)換為大寫形式:
{{ "San Francisco is very cloudy" | uppercase }}
<!-- SAN FRANCISCO IS VERY CLOUDY -->
自定義過濾器
創(chuàng)建自定義過濾器需要將它放到自己的模塊中询一。下面我們來實(shí)現(xiàn)一個(gè)過濾器隐孽,將字符串第一個(gè)字母轉(zhuǎn)換為大寫癌椿。
angular.module('myApp.filters', [])
.filter('capitalize', function() {
return function(input) {
// input是我們傳入的字符串
if (input) {
return input[0].toUpperCase() + input.slice(1);
}
});
過濾器本質(zhì)上是一個(gè)會把我們輸入的內(nèi)容當(dāng)作參數(shù)傳入進(jìn)去的函數(shù)。
??現(xiàn)在菱阵,如果想將一個(gè)句子的首字母轉(zhuǎn)換成大寫形式踢俄,可以用過濾器先將整個(gè)句子都轉(zhuǎn)換成小寫,再把首字母轉(zhuǎn)換成大寫:
<!-- Ginger loves dog treats -->
{{ 'ginger loves dog treats' | lowercase | capitalize }}
表單驗(yàn)證
要使用表單驗(yàn)證晴及,首先要確保表單有一個(gè)name屬性都办。所有輸入字段都可以進(jìn)行基本的驗(yàn)證,比如最大虑稼、最小長度等琳钉。這些功能是由新的HTML5表單屬性提供的。
??如果想要屏蔽瀏覽器對表單的默認(rèn)驗(yàn)證行為蛛倦,可以在表單元素上添加novalidate
標(biāo)記歌懒。
??下面看一下可以在input元素上使用的所有驗(yàn)證選項(xiàng)。
1.必填項(xiàng)
驗(yàn)證某個(gè)表單輸入是否已填寫溯壶,只要在輸入字段元素上添加HTML5標(biāo)記required
即可:
<input type="text" required />
2.最小長度
驗(yàn)證表單輸入的文本長度是否大于某個(gè)最小值及皂,在輸入字段上使用AngularJS指令ng-minlength="{number}"
:
<input type="text" ng-minlength="5" />
3. 最大長度
驗(yàn)證表單輸入的文本長度是否小于或等于某個(gè)最大值,在輸入字段上使用AngularJS指令ng-maxlength="{number}"
:
<input type="text" ng-maxlength="20" />
4. 模式匹配
使用ng-pattern="/PATTERN/"
來確保輸入能夠匹配指定的正則表達(dá)式:
<input type="text" ng-pattern="[a-zA-Z]" />
5. 電子郵件
驗(yàn)證輸入內(nèi)容是否是電子郵件:
<input type="email" name="email" ng-model="user.email" />
6. 數(shù)字
驗(yàn)證輸入內(nèi)容是否是數(shù)字:
<input type="number" name="age" ng-model="user.age" />
7. URL
驗(yàn)證輸入內(nèi)容是否是URL:
<input type="url" name="homepage" ng-model="user.facebook_url" />
8. 在表單中控制變量
表單的屬性可以在其所屬的$scope對象中訪問到且改,而我們又可以訪問$scope對象验烧,因此JavaScript可以間接地訪問DOM中的表單屬性。借助這些屬性又跛,我們可以對表單做出實(shí)時(shí)響應(yīng)碍拆。這些屬性包括下面這些。
(注意慨蓝,可以使用下面的格式訪問這些屬性倔监。)
formName.inputFieldName.property
-
未修改的表單
這是一個(gè)布爾屬性,用來判斷用戶是否修改了表單菌仁。如果未修改浩习,值為true,如果修改過值為false:
formName.inputFieldName.$pristine
-
修改過的表單
只要用戶修改過表單济丘,無論輸入是否通過驗(yàn)證谱秽,該值都返回true:
formName.inputFieldName.$dirty
-
合法的表單
這個(gè)布爾型的屬性用來判斷表單的內(nèi)容是否合法。如果當(dāng)前表單內(nèi)容是合法的摹迷,下面屬性的值就是true:
formName.inputFieldName.$valid
-
不合法的表單
這個(gè)布爾屬性用來判斷表單的內(nèi)容是否不合法疟赊。如果當(dāng)前表單內(nèi)容是不合法的,下面屬性的值為true:
formName.inputFieldName.$invalid
-
錯(cuò)誤
這是AngularJS提供的另外一個(gè)非常有用的屬性:$error
對象峡碉。它包含當(dāng)前表單的所有驗(yàn)證內(nèi)容近哟,以及它們是否合法的信息。用下面的語法訪問這個(gè)屬性:
formName.inputfieldName.$error
如果驗(yàn)證失敗鲫寄,這個(gè)屬性的值為true吉执;如果值為false疯淫,說明輸入字段的值通過了驗(yàn)證。
9. 一些有用的CSS樣式
AngularJS處理表單時(shí)戳玫,會根據(jù)表單當(dāng)前的狀態(tài)添加一些CSS類熙掺。
它們包括:
.ng-pristine {}
.ng-dirty {}
.ng-valid {}
.ng-invalid {}
它們對應(yīng)著表單輸入字段的特定狀態(tài)。
??當(dāng)某個(gè)字段中的輸入非法時(shí)咕宿,.ng-invlid
類會被添加到這個(gè)字段上:
input.ng-invalid {
border: 1px solid red;
}
input.ng-valid {
border: 1px solid green;
}
-
$parsers
當(dāng)用戶同控制器進(jìn)行交互币绩,并且ngModelController
中的$setViewValue()
方法被調(diào)用時(shí),$parsers
數(shù)組中的函數(shù)會以流水線的形式被逐個(gè)調(diào)用府阀。第一個(gè)$parse
被調(diào)用后缆镣,執(zhí)行結(jié)果會傳遞給第二個(gè)$parse
,以此類推试浙。
??這些函數(shù)可以對輸入值進(jìn)行轉(zhuǎn)換董瞻,或者通過$setValidity()
函數(shù)設(shè)置表單的合法性。
??使用$parsers
數(shù)組是實(shí)現(xiàn)自定義驗(yàn)證的途徑之一川队。例如,假設(shè)我們想要確保輸入值在某兩個(gè)數(shù)值之間睬澡,可以在$parsers
數(shù)組中入棧一個(gè)新的函數(shù)固额,這個(gè)函數(shù)會在驗(yàn)證鏈中被調(diào)用。每個(gè)$parser
返回的值都會被傳入下一個(gè)$parser
中煞聪。當(dāng)不希望數(shù)據(jù)模型發(fā)生更新時(shí)返回undefined
斗躏。
angular.module('myApp')
.directive('oneToTen', function() {
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
ngModel.$parsers.unshift(
function(viewValue) {
var i = parseInt(viewValue);
if (i >= 0 && i < 10) {
ngModel.$setValidity('oneToTen', true);
return viewValue;
} else {
ngModel.$setValidity('oneToTen', false);
return undefined;
}
});
}
};
});
-
$formatters
當(dāng)綁定的ngModel
值發(fā)生了變化,并經(jīng)過$parsers
數(shù)組中解析器的處理后昔脯,這個(gè)值會被傳遞給$formatters
流水線啄糙。同$parsers
數(shù)組可以修改表單的合法性狀態(tài)類似,$formatters
中的函數(shù)也可以修改并格式化這些值云稚。
??比起單純的驗(yàn)證目的隧饼,這些函數(shù)更常用來處理視圖中的可視變化。例如静陈,假設(shè)我們要對某個(gè)值進(jìn)行格式化燕雁。通過$formatters
數(shù)組可以在這個(gè)值上執(zhí)行過濾器:
angular.module('myApp')
.directive('oneToTen', function() {
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
ngModel.$formatters.unshift(function(v) {
return $filter('number')(v);
});
}
};
});
10. 組合實(shí)例
下面我們一起創(chuàng)建一個(gè)注冊表單。表單中包括用戶的名字鲸拥、郵件地址以及用戶名拐格。
下面開始定義表單:
<form name="signup_form" novalidateng-submit="signupForm()">
<fieldset>
<legend>Signup</legend>
<button type="submit" class="button radius">Submit</button>
</fieldset>
</form>
這個(gè)表單的名稱是signup_form
,當(dāng)表單提交時(shí)我們要調(diào)用signupForm()
刑赶。
下面添加用戶的名字:
<div class="row">
<div class="large-12 columns">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name" ng-minlength="3" ng-maxlength="20" required />
</div>
</div>
我們添加了一個(gè)表單捏浊,這個(gè)表單有一個(gè)名為name的輸入字段,并且這個(gè)輸入字段被ng-model
指令綁定到了$scope
對象的signup.name
上撞叨。
用$dirty
屬性來確保用戶未對輸入內(nèi)容進(jìn)行修改時(shí)錯(cuò)誤內(nèi)容不會顯示出來:
<divclass="row">
<div class="large-12 columns">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name" ng-minlength="3" ng-maxlength="20" required />
<div class="error" ng-show="signup_form.name.$dirty && signup_form.name.$invalid">
<small class="error" ng-show="signup_form.name.$error.required">
Your name is required.
</small>
<small class="error" ng-show="signup_form.name.$error.minlength">
Your name is required to be at least 3 characters
</small>
<small class="error" ng-show="signup_form.name.$error.maxlength">
Your name cannot be longer than 20 characters
</small>
</div>
</div>
</div>
將整個(gè)過程分開來看金踪,我們只是像以前一樣在表單發(fā)生改變浊洞,且輸入內(nèi)容不合法時(shí)才展示錯(cuò)誤內(nèi)容。現(xiàn)在热康,我們會在特定的屬性未通過驗(yàn)證時(shí)只展示對應(yīng)的特定DOM元素沛申。
接下來看下一組驗(yàn)證,電子郵箱的驗(yàn)證:
<div class="row">
<div class="large-12 columns">
<label>Your email</label>
<input type="email" placeholder="Email" name="email" ng-model="signup.email" ng-minlength="3" ng-maxlength="20" required />
<div class="error" ng-show="signup_form.email.$dirty && signup_form.email.$invalid">
<small class="error" ng-show="signup_form.email.$error.required">
Your email is required.
</small>
<small class="error" ng-show="signup_form.email.$error.minlength">
Your email is required to be at least 3 characters
</small>
<small class="error" ng-show="signup_form.email.$error.email">
That is not a valid email. Please input a valid email.
</small>
<small class="error" ng-show="signup_form.email.$error.maxlength">
Your email cannot be longer than 20 characters
</small>
</div>
</div>
</div>
現(xiàn)在整個(gè)表單都被包含進(jìn)來了姐军,我們來看一下電子郵件的輸入字段铁材。注意,我們將輸入字段的type屬性設(shè)置為email奕锌,并且在$error.email
上添加了驗(yàn)證錯(cuò)誤的信息著觉。這個(gè)驗(yàn)證同時(shí)基于AngularJS和HTML5屬性實(shí)現(xiàn)。
最后惊暴,看一下用戶名的輸入字段:
<div class="large-12 columns">
<label>Username</label>
<input type="text" placeholder="Desired username" name="username" ng-model="signup.username" ng-minlength=3 ng-maxlength=20 ensure-unique="username" required />
<div class="error" ng-show="signup_form.username.$dirty && signup_form.username.$invalid">
<small class="error" ng- show="signup_form.username.$error.required">
Please input a username
</small>
<small class="error" ng-show="signup_form.username.$error.minlength">
Your username is required to be at least 3 characters
</small>
<small class="error" ng-show="signup_form.username.$error.maxlength">
Your username cannot be longer than 20 characters
</small>
<small class="error" ng-show="signup_form.username.$error.unique">
That username is taken, please try another
</small>
</div>
</div>
在最后一個(gè)輸入字段中除了同前面相同的驗(yàn)證外饼丘,還添加了一個(gè)自定義驗(yàn)證。這個(gè)自定義驗(yàn)證是用AngularJS指令定義的:
app.directive('ensureUnique', function($http) {
return {
require: 'ngModel',
link: function(scope, ele, attrs, c) {
scope.$watch(attrs.ngModel, function(n) {
if (!n) return;
$http({
method: 'POST',
url: '/api/check/' + attrs.ensureUnique,
data: {
field: attrs.ensureUnique,
value: scope.ngModel
}
}).success(function(data) {
c.$setValidity('unique', data.isUnique);
}).error(function(data) {
c.$setValidity('unique', false);
});
});
}
};
});
當(dāng)表單內(nèi)容通過驗(yàn)證后辽话,會向/api/check/username
發(fā)送一個(gè)POST請求來驗(yàn)證用戶名是否可用肄鸽。
??最后,把按鈕放進(jìn)去油啤〉渑牵可以用ng-disabled
指令基于表單的合法性來啟用或禁用按鈕:
<button type="submit" ng-disabled="signup_form.$invalid" class="button radius">Submit</button>
盡管實(shí)時(shí)驗(yàn)證非常有用,但是當(dāng)用戶還沒有完成輸入時(shí)就彈出一個(gè)錯(cuò)誤提示益咬,這種體驗(yàn)是非常糟糕的逮诲。應(yīng)該在用戶提交表單或完成當(dāng)前字段中的輸入后,再提示驗(yàn)證信息幽告,這樣才是用戶友好的梅鹦。下面看看如何實(shí)現(xiàn)這兩種效果。
- 在提交后顯示驗(yàn)證信息
當(dāng)用戶試圖提交表單時(shí)冗锁,你可以在作用域中捕獲到一個(gè)submitted
值齐唆,然后對表單內(nèi)容進(jìn)行驗(yàn)證并顯示錯(cuò)誤信息。
例如冻河,修改一下前面的例子蝶念,只在用戶提交表單時(shí)才顯示錯(cuò)誤信息。在ng-show
指令中加入對表單是否進(jìn)行了提交的檢查:
<form name="signup_form" novalidate ng-submit="signupForm()" ng-controller="signupController">
<fieldset>
<legend>Signup</legend>
<div class="row">
<div class="large-12 columns">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name" ng-minlength="3" ng-maxlength="20" required />
<div class="error" ng-show="signup_form.name.$dirty && signup_form.name.$invalid && signup_form.submitted">
<small class="error" ng-show="signup_form.name.$error.required">
Your name is required.
</small>
<small class="error" ng-show="signup_form.name.$error.minlength">
Your name is required to be at least 3 characters
</small>
<small class="error" ng-show="signup_form.name.$error.maxlength">
Your name cannot be longer than 20 characters
</small>
</div>
</div>
</div>
<button type="submit" >Submit</button>
</fieldset>
</form>
現(xiàn)在芋绸,僅當(dāng)signup_form.submitted
設(shè)置為true時(shí)媒殉,容納錯(cuò)誤信息的div才會展示出來。在signupForm
操作中實(shí)現(xiàn)這個(gè)行為摔敛,如下所示:
app.controller('signupController', function($scope) {
$scope.submitted = false;
$scope.signupForm = function() {
if ($scope.signup_form.$valid) {
// 正常提交
} else {
$scope.signup_form.submitted = true;
}
}
});
如果用戶試圖在有非法輸入的情況下提交表單廷蓉,我們現(xiàn)在可以捕獲到這個(gè)行為并展示合適的錯(cuò)誤信息。
- 在失焦后顯示驗(yàn)證信息
如果想保留實(shí)時(shí)錯(cuò)誤提示的體驗(yàn),可以在用戶從某個(gè)輸入字段失焦后提示錯(cuò)誤信息(例如用戶已經(jīng)不在某個(gè)特定的輸入字段中時(shí))桃犬。為了實(shí)現(xiàn)這個(gè)效果刹悴,需要實(shí)現(xiàn)一個(gè)不是很復(fù)雜的指令,并向表單中添加一個(gè)新的變量攒暇。
我們需要使用的指令是ngFocus
土匀,它是這樣的:
app.directive('ngFocus', [function() {
var FOCUS_CLASS = "ng-focused";
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
ctrl.$focused = false;
element.bind('focus', function(evt) {
element.addClass(FOCUS_CLASS);
scope.$apply(function() {
ctrl.$focused = true;
});
}).bind('blur', function(evt) {
element.removeClass(FOCUS_CLASS);
scope.$apply(function() {
ctrl.$focused = false;
});
});
}
};
}]);
將ngFocus
指令添加到input
元素上就可以使用這個(gè)指令,如下所示:
<input ng-class="{error: signup_form.name.$dirty && signup_form.name.$invalid}"
type="text"
placeholder="Name"
name="name"
ng-model="signup.name"
ng-minlength="3"
ng-maxlength="20" required ng-focus />
ngFocus
指令給表單輸入字段的blur
和focus
添加了對應(yīng)的行為形用,添加了一個(gè)名為ng-focused
的類就轧,并將$focused
的值設(shè)置為true。接下來田度,可以根據(jù)表單是否具有焦點(diǎn)來展示獨(dú)立的錯(cuò)誤信息妒御。如下所示:
<div class="error" ng-show="signup_form.name.$dirty && signup_form.name.$invalid && !signup_form.name.$focused">
也可以在ngModel
控制器中使用$isEmpty()
方法來判斷輸入字段是否為空。當(dāng)輸入字段為空這個(gè)方法會返回true镇饺,反之如果不為空則返回false乎莉。
ngMessages(1.3+)
Angular 1.3中,Angular核心做了一個(gè)升級奸笤。它不再需要基于一個(gè)詳細(xì)的表達(dá)式狀態(tài)創(chuàng)建元素顯示或隱藏惋啃。
<form name="signup_form" novalidate ng-submit="signupForm()" ng-controller="signupController">
<fieldset>
<legend>Signup</legend>
<div class="row">
<div class="large-12 columns">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name" ng-minlength=3 ng-maxlength=20 required />
<div class="error" ng-show="signup_form.name.$dirty && signup_form.name.$invalid && signup_form.submitted">
<small class="error" ng-show="signup_form.name.$error.required">
Your name is required.
</small>
<small class="error" ng-show="signup_form.name.$error.minlength">
Your name is required to be at least 3 characters
</small>
<small class="error" ng-show="signup_form.name.$error.maxlength">
Your name cannot be longer than 20 characters
</small>
</div>
</div>
</div>
<button type="submit">Submit</button>
</fieldset>
</form>
本質(zhì)上這一功能會檢查錯(cuò)誤對象的狀態(tài)發(fā)生了變化。此外监右,我們還得到了站點(diǎn)中每個(gè)表單需要的很多額外的和重復(fù)的標(biāo)記边灭。這顯然不是一個(gè)理想的解決方案。
從1.3開始秸侣,Angular中新增了一個(gè)ngMessages
指令存筏。
安裝
安裝ngMessages
很簡單宠互,因?yàn)樗淮虬闪艘粋€(gè)Angular模塊味榛。首先下載這個(gè)模塊:
$ bower install --save angular-messages
或者,也可以從angular.org
下載該文件并將它保存到項(xiàng)目中予跌。還需要將angular-messages.js
這個(gè)JavaScript引入我們的主HTML中:
<script type="text/javascript" src="bower_components/angular-messages/angular-messages.js"></script>
最后搏色,我們還要告訴Angular將ngMessages
作為應(yīng)用程序的依賴模塊引入:
angular.module('myApp', ['ngMessages']);
使用ngMessages
:
<form name="signup_form" novalidate ng-submit="signupForm()" ng-controller="signupController">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name" ng-minlength=3 ng-maxlength=20 required />
<div class="error" ng-messages="signup_form.name.$error">
<div ng-message="required">Make sure you enter your name</div>
<div ng-message="minlength">Your name must be at least 3 characters</div>
<div ng-message="maxlength">Your name cannot be longer than 20 characters</div>
</div>
<button type="submit">Submit</button>
</form>
然而對于這個(gè)實(shí)現(xiàn)些举,一次只會顯示一個(gè)錯(cuò)誤消息筑舅。如果我們想要更新這個(gè)實(shí)現(xiàn)同時(shí)顯示所有的錯(cuò)誤將會怎樣界弧?很容易哮伟。只需在ng-message
指令旁邊使用ng-messages-multiple
屬性即可膜毁。
<div class="error" ng-messages="signup_form.name.$error" ng-messages-multiple>
<div ng-message="required"> sure you enter your name</div>
<div ng-message="minlength">Your name must be at least 3 characters</div>
<div ng-message="maxlength">Your name cannot be longer than 20 characters</div>
</div>
很多時(shí)候這些信息相互之間非常相似萄凤。我們可以將它們保存到模板中從而減少麻煩躏升,而不是重新輸入每個(gè)字段的錯(cuò)誤信息溯革。
<!-- In templates/errors.html -->
<div ng-message="required">This field is required</div>
<div ng-message="minlength">The field must be at least 3 characters</div>
<div ng-message="maxlength">The field cannot be longer than 20 characters</div>
然后我們可以通過在視圖中使用ng-messages-include屬性引入這個(gè)模板來改進(jìn)這個(gè)表單:
<div class='error' ng-messages="signup_form.name.$error" ng-messages-include="templates/errors.html"></div>
有時(shí)骄蝇,你可能希望為不同的字段自定義錯(cuò)誤信息膳殷。沒問題,你可以在這個(gè)指令內(nèi)簡單地插入一個(gè)自定義錯(cuò)誤信息九火。由于ngMessages
涉及ngMessages
容器中錯(cuò)誤列表的順序赚窃,我們可以通過在這個(gè)指令中列出自定義錯(cuò)誤信息的方式覆蓋它們册招。
<div class="error" ng-messages="signup_form.name.$error" ng-messages-include="templates/errors.html">
<!--除了minlength會被覆蓋之外,其他每個(gè)信息都會保持不變-->
</div>
此外勒极,甚至還可以為自定義驗(yàn)證創(chuàng)建自定義消息是掰。可以通過修改模型的$ parsers鏈做到這一點(diǎn)辱匿。
例如键痛,比方說我們想要創(chuàng)建一個(gè)自定義驗(yàn)證器驗(yàn)證用戶名在一個(gè)注冊表單中是否有效:
app.directive('ensureUnipue', function($http) {
return {
require: 'ngModel',
link: function(scope, ele, attrs, ctrl) {
ctrl.$parsers.push(function(val) {
// 在這里添加驗(yàn)證
});
}
}
});
對于ngModel
,你可以添加可以使用ngMessage
指令顯示/隱藏的自定義信息掀鹅。還可以添加可以使用ngMessage
指令檢查的帶有自定義的消息的指令散休。例如,改變前面使用ngMessages
的例子乐尊。
<form name="signup_form" novalidate ng-submit="signupForm()" ng-controller="signupController" ensure-unique="/api/checkUsername.json">
<label>Your name</label>
<input type="text" placeholder="Username" name="username" ng-model="signup.username" ng-minlength=3 ng-maxlength=20 required />
<div class="error" ng-messages="signup_form.username.$error">
<div ng-message="required">
Make sure you enter your username
</div>
<div ng-message="checkingAvailability">
Checking...
</div>
<div ng-message="usernameAvailablity">
The username has already been taken. Please choose another
</div>
</div>
<button type="submit">Submit</button>
</form>
在這種用法中戚丸,我們檢查了錯(cuò)誤信息的自定義屬性。為了添加自定義錯(cuò)誤消息扔嵌,我們將會把它們應(yīng)用到自定義ensureUnique
指令的ngModel
中限府。
app.directive('ensureUnique', function($http) {
return {
require: 'ngModel',
link: function(scope, ele, attrs, ctrl) {
var url = attrs.ensureUnique;
ctrl.$parsers.push(function(val) {
if (!val || val.length === 0) {
return;
}
ngModel.$setValidity('checkingAvailability', true);
ngModel.$setValidity('usernameAvailablity', false);
$http({
method: 'GET',
url: url,
params: {
username: val
}
}).success(function() {
ngModel.$setValidity('checkingAvailability', false);
ngModel.$setValidity('usernameAvailablity', true);
})['catch'](function() {
ngModel.$setValidity('checkingAvailability', false);
ngModel.$setValidity('usernameAvailablity', false);
});
return val;
})
}
}
});