[TOC]
## 第七章 過濾器
**格式化** 需要展示給用戶的 **數據**.
```html
{{ expr | filter : arg1 : arg2 : ... | filter2 | filterN}}
```
eg:
```javascript
app.controller('DemoController', ['$scope', '$filter', function($scope, $filter){
$scope.name = $filter('lowercase')('AIR');
}]);
```
### 7.0 常用過濾器
#### 7.0.1 {{ number | currency }
#### 7.0.2 {{ today | date:'yyyy-MM-dd HH:mm:ss.sss' }
#### 7.0.3 {{ array | filter:[string|object|function] }}
可以從給定數組中選擇一個子集,并將其生成一個新數組返回.
> 1) string 返回所有包含這個字符串的元素.如果返回不包含前面加 "**!***" .
```
$scope.words = ['Ari','Lerner','Likes','To','Eat','Pizza'];
{{ words | filter:'e' }} <!-- ["Lerner","Likes","Eat"] -->
{{ words | filter:'!e' }} <!-- ["Ari","To","Pizza"] -->
```
> 2) object 會將待過濾對象的屬性同這個對象中的同名屬性進行比較, 如果屬性值是字符串就會判斷是否 **包含** 該字符串. 如果我們希望對全部屬性進行對比, 可以將 $ 當作鍵名.
```html
<script>
$scope.students = [
{
'name': 'Ari',
'City': 'San Francisco',
'favorite food': 'Pizza'
},{
'name': 'Nate',
'City': 'San Francisco',
'favorite food': 'indian food'
}
];
</script>
{{ students | filter:{'favorite food': 'Pizza'} }}
<!-- [{"name":"Ari","City":"SanFrancisco","favoritefood":"Pizza"}] -->
{{ students | filter:{$:'!a'} }} <!-- 集合中所有屬性不含'a' 的元素 -->
```
> 3) function 對每個元素都執行這個函數, 返回非假值的元素會出現在新的數組中并返回.
```html
<script>
...
$scope.words = ['Ari','likes','to','travel'];
...
$scope.isCapitalized = function(str) {
return str[0] == str[0].toUpperCase();
};
...
</script>
{{ words | filter:isCapitalized }} <!-- ["Ari"] -->
```
#### 7.0.4 json
json過濾器可以將一個JSON或JavaScript對象轉換成字符串。
```html
{{ {'name': 'Ari', 'City': 'SanFrancisco'} | json }}
<!--{"name": "Ari","City": "San Francisco"}-->
```
#### 7.0.5 limitTo
string | array -> 截取
>string
```html
{{ 'San Francisco is very cloudy' | limitTo:3 }}
<!-- San -->
{{ 'San Francisco is very cloudy' | limitTo:-6 }}
<!-- cloudy -->
```
>array
```html
{{ ['a','b','c','d','e','f'] | limitTo:1 }}
<!-- ["a"] -->
```
#### 7.0.6 lowercase
```html
{{ "San Francisco is very cloudy" | lowercase }}
<!-- san francisco is very cloudy -->
```
#### 7.0.7 uppercase
```html
{{ "San Francisco is very cloudy" | uppercase }}
<!-- SAN FRANCISCO IS VERY CLOUDY -->
```
#### 7.0.8 number
```html
{{ 123456789 | number }}
<!-- 1,234,567,890 -->
{{ 1.234567 | number:2 }}
<!-- 1.23 -->
```
#### 7.0.9 **orderBy**
```html
<script>
$scope.students = [
{ 'name': 'Ari', 'status': 'awake' }
,{ 'name': 'Q', 'status': 'sleeping' }
,{ 'name': 'Nate', 'status': 'awake' }
];
</script>
{{ students | orderBy:'name' }}
<!--
[
{"name":"Ari","status":"awake"},
{"name":"Nate","status":"awake"},
{"name":"Q","status":"sleeping"}
]
-->
// 排序強制反轉
{{ students | orderBy:'name':true }}
<!--
[
{"name":"Ari","status":"awake"},
{"name":"Nate","status":"awake"},
{"name":"Q","status":"sleeping"}
]
-->
```
### 7.1 自定義過濾器
```html
angular.module('myApp.filters', [])
.filter('capitalize', function() {
return function(input) {
// code here
};
});
```
> 范例
```html
angular.module('myApp.filters', [])
.filter('capitalize', function() {
return function(input) {
// input是我們傳入的字符串
if (input) {
return input[0].toUpperCase() + input.slice(1);
}
}
});
```
> 鏈式過濾器
```html
<!-- Ginger loves dog treats -->
{{ 'ginger loves dog treats' | lowercase | capitalize }}
```
### 7.2 表單驗證
雖然不能完全依賴 js 表單驗證,但是我們還是要在Web前端盡力保護后端。
AngularJS能夠將HTML5表單驗證功能同它自己的驗證指令結合起來使用。
```html
<form name="form" novalidate>
<label name="email">Your email</label>
<input type="email" name="email" ng-model="email" placeholder="Email Address" />
</form>
```
#### 7.2.0 novalidate
如果想要屏蔽瀏覽器對表單的默認驗證行為,可以在表單元素上添加novalidate標記。
#### 7.2.1 必填項 required
```html
<input type="text" required />
```
#### 7.2.2 最小長度 ng-minlength="{number}"
```html
<input type="text" ng-minlength="5" />
```
#### 7.2.3 最大長度 ng-maxlength="{number}"
```html
<input type="text" ng-maxlength="20" />
```
#### 7.2.4 模式匹配 ng-pattern="/PATTERN/"
```html
<input type="text" ng-pattern="/[a-zA-Z]/" />
```
#### 7.2.5 電子郵件 type="email"
```html
<input type="email" name="email" ng-model="user.email" />
```
#### 7.2.6 數字 type="number"
```html
<input type="number" name="age" ng-model="user.age" />
```
#### 7.2.7 URL type="url"
```html
<input type="url" name="homepage" ng-model="user.url" />
```
#### 7.2.8 自定義驗證 指令(directive)
ajax
#### 7.2.9 在表單中控制變量
表單的屬性可以在其所屬的$scope對象中訪問到
```javascript
$scope.formName.inputName.property;
// eg:
$scope.formName.inputName = {
$name : string,
$modelValue : string,
$viewValue : string,
$pristine : boolean,
$dirty : boolean,
$valid : boolean,
$invalid : boolean,
$error : object,
$setViewValue : function,
$setPristine : function,
$setValidity : function,
$viewChangeListener : array
$isEmpty : function,
$parsers : array[function],
$formatters : array[function],
};
```
* 未修改的表單
```javascript
$scope.formName.inputName.$pristine // boolean
```
* 修改過的表單
```javascript
$scope.formName.inputName.$dirty // boolean
```
* 合法的表單
```javascript
$scope.formName.inputName.$valid // boolean
```
* 不合法的表單
```javascript
$scope.formName.inputName.$invalid // boolean
```
* 錯誤
```javascript
$scope.formName.inputName.$error // object = { pattern : true, ... }
```
#### 7.2.10 CSS
它們對應著表單輸入字段的特定狀態。
.ng-pristine {}
.ng-dirty {}
.ng-valid, .ng-valid-xxx {}
.ng-invalid, ng-invalid-xxx {}
當某個字段中的 **輸入非法** 時,`.ng-invlid` 類會被添加到這個字段上。
#### $parsers
當用戶同控制器進行交互,并且ngModelController中的$setViewValue()方法被調用時,$parsers數組中的函數會以流水線的形式被逐個調用。第一個$parse被調用后,執行結果會傳遞給第二個$parse,以此類推。
這些函數可以對輸入值進行轉換,或者通過$setValidity()函數設置表單的合法性。
使用$parsers數組是實現自定義驗證的途徑之一。例如,假設我們想要確保輸入值在某兩個數值之間,可以在$parsers數組中入棧一個新的函數,這個函數會在驗證鏈中被調用。
每個$parser返回的值都會被傳入下一個$parser中。當不希望數據模型發生更新時返回
undefined。
```javascript
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
當綁定的ngModel值發生了變化,并經過$parsers數組中解析器的處理后,這個值會被傳遞給$formatters流水線。同$parsers數組可以修改表單的合法性狀態類似,$formatters中的函數也可以修改并格式化這些值。
比起單純的驗證目的,這些函數更常用來處理視圖中的可視變化。例如,假設我們要對某個值進行格式化。通過$formatters數組可以在這個值上執行過濾器:
```javascript
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);
});
}
};
});
```