[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);
});
}
};
});
```