Angular學(xué)習(xí)筆記(2)—過濾器

過濾器用來格式化需要展示給用戶的數(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指令給表單輸入字段的blurfocus添加了對應(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;
            })
        }
    }
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痢缎,隨后出現(xiàn)的幾起案子胁勺,更是在濱河造成了極大的恐慌,老刑警劉巖独旷,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件署穗,死亡現(xiàn)場離奇詭異,居然都是意外死亡嵌洼,警方通過查閱死者的電腦和手機(jī)案疲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來麻养,“玉大人褐啡,你說我怎么就攤上這事”畈” “怎么了备畦?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長许昨。 經(jīng)常有香客問我懂盐,道長,這世上最難降的妖魔是什么糕档? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任莉恼,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘类垫。我一直安慰自己司光,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布悉患。 她就那樣靜靜地躺著残家,像睡著了一般。 火紅的嫁衣襯著肌膚如雪售躁。 梳的紋絲不亂的頭發(fā)上坞淮,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音陪捷,去河邊找鬼回窘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛市袖,可吹牛的內(nèi)容都是我干的啡直。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼苍碟,長吁一口氣:“原來是場噩夢啊……” “哼酒觅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起微峰,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤舷丹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蜓肆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颜凯,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年仗扬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了症概。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厉颤,死狀恐怖穴豫,靈堂內(nèi)的尸體忽然破棺而出凡简,到底是詐尸還是另有隱情逼友,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布秤涩,位于F島的核電站帜乞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏筐眷。R本人自食惡果不足惜黎烈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧照棋,春花似錦资溃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至符隙,卻和暖如春趴捅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背霹疫。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工拱绑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丽蝎。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓猎拨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屠阻。 傳聞我的和親對象是個(gè)殘疾皇子迟几,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)栏笆,斷路器类腮,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • ng-model 指令ng-model 指令 綁定 HTML 元素 到應(yīng)用程序數(shù)據(jù)。ng-model 指令也可以:...
    壬萬er閱讀 861評論 0 2
  • 指令定義 對于指令蛉加,可以把它簡單的理解成在特定DOM元素上運(yùn)行的函數(shù)蚜枢,指令可以擴(kuò)展這個(gè)元素的功能。??我們可以自己...
    oWSQo閱讀 1,179評論 0 0
  • AngularJS是什么 AngularJS的官方文檔這樣介紹它: 完全使用JavaScript編寫的客戶端技術(shù)针饥。...
    oWSQo閱讀 1,304評論 0 10
  • 下班后厂抽,一個(gè)人買了夠很多人吃的菜,打電話約完了半徑1000米之內(nèi)的朋友丁眼,不是太忙就是晚飯?jiān)缬邪才趴攴铮瓉砉陋?dú)不...
    一謠閱讀 548評論 6 1