过滤器在指令将数据处理并显示到视图之前,对数据进行转换而不必修改作用域中原有的数据,这样能够允许同一份数据在应用中的不同部分以不同形式展示。
过滤器可以执行任何类型的转换,多少情况下用于格式化或对数据进行排序。
一些内置过滤器以及相关知识点:
- currency 格式化为货币
- number 格式化通用数字
- date 格式化为日期
- uppercase/lowercase 大小写
- json 将js对象转化为json格式
- 通过script向html添加本地文件
- limitTo 规定数量的数组中的元素
- orderBy 对数组进行排序
- Module.filter 指定工厂函数,生成一个执行过滤器函数
- 使用$filter 服务,访问和调用其它过滤器
为什么不在控制器中过滤数据?
有的时候,将数据转换或格式化的逻辑放在控制器中时很方便而且快捷的事儿,为什么需要将过滤器放在视图中使用呢?
主要是因为,在控制器中转换数据然后直接输出限制了数据的使用方式,因为只有转化后的而没有原始数据,就无法将这个数据用在其他方法或视图中了。
使用过滤器的好处在于,能保留作用域中数据的完整性,将格式化逻辑放在控制器之外意味着能在整个应用中使用,且易于测试和维护。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 
 | <html ng-app="exampleApp"><head>
 <title>Filters</title>
 <script src="angular.js"></script>
 <link href="bootstrap.css" rel="stylesheet" />
 <link href="bootstrap-theme.css" rel="stylesheet" />
 <script>
 angular.module("exampleApp", [])
 .controller("defaultCtrl", function ($scope) {
 $scope.products = [
 { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
 { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
 { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 },
 
 
 ];
 
 $scope.getExpiryDate = function (days) {
 var now = new Date();
 return now.setDate(now.getDate() + days);
 }
 });
 </script>
 </head>
 <body ng-controller="defaultCtrl">
 <div class="panel panel-default">
 <div class="panel-heading">
 <h3>
 Products
 <span class="label label-primary">{{products.length}}</span>
 </h3>
 </div>
 <div class="panel-body">
 <table class="table table-striped table-bordered table-condensed">
 <thead>
 <tr>
 <td>Name</td><td>Category</td>
 <td>Expiry</td><td class="text-right">Price</td>
 </tr>
 </thead>
 <tbody>
 <tr ng-repeat="p in products">
 <td>{{p.name | uppercase }}</td>
 <td>{{p.category | lowercase }}</td>
 <td>{{getExpiryDate(p.expiry) | date:"dd MMM yy"}}</td>
 <td class="text-right">${{p.price | number:0 }}</td>
 </tr>
 
 </tbody>
 </table>
 </div>
 </div>
 </body>
 </html>
 
 | 
其中,date过滤器支持一些快捷格式字符串:
- medium 相当于MMM d, y h:mm:ss a
- short M/d/yy h:mm a
 …
过滤集合
ng包含三个内置的集合过滤器,同时也支持自定义过滤器。
limitTo可以限制数组中取出的项目的数量
filter过滤器用于从数据中选择一些对象,条件为指定的表达式,或者一个函数
orderBy可对数组中的对象进行排序,指定一个表达式或函数,最简单的是指定为属性名,若在属性名前加负号,表示排序方向
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 
 | <html ng-app="exampleApp"><head>
 <title>Filters</title>
 <script src="angular.js"></script>
 <link href="bootstrap.css" rel="stylesheet" />
 <link href="bootstrap-theme.css" rel="stylesheet" />
 <script>
 angular.module("exampleApp", [])
 .controller("defaultCtrl", function ($scope) {
 $scope.products = [
 { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
 { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
 { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 },
 
 { name: "Tuna", category: "Fish", price: 20.45, expiry: 3 },
 { name: "Salmon", category: "Fish", price: 17.93, expiry: 2 },
 { name: "Trout", category: "Fish", price: 12.93, expiry: 4 },
 
 { name: "Beer", category: "Drinks", price: 2.99, expiry: 365 },
 { name: "Wine", category: "Drinks", price: 8.99, expiry: 365 },
 { name: "Whiskey", category: "Drinks", price: 45.99, expiry: 365 }
 ];
 
 $scope.limitVal = "5";
 $scope.limitRange = [];
 for (var i = (0 - $scope.products.length);
 i <= $scope.products.length; i++) {
 $scope.limitRange.push(i.toString());
 }
 
 
 $scope.selectItems = function (item) {
 return item.category == "Fish" || item.name == "Beer";
 };
 
 
 $scope.myCustomSorter = function (item) {
 return item.expiry < 5 ? 0 : item.price;
 }
 });
 </script>
 </head>
 <body ng-controller="defaultCtrl">
 <div class="panel panel-default">
 <div class="panel-heading">
 <h3>
 Products
 <span class="label label-primary">{{products.length}}</span>
 </h3>
 </div>
 <div class="panel-body">
 Limit: <select ng-model="limitVal"
 ng-options="item for item in limitRange"></select>
 </div>
 <div class="panel-body">
 
 <table class="table table-striped table-bordered table-condensed">
 <thead>
 <tr>
 <td>Name</td>
 <td>Category</td>
 <td>Expiry</td>
 <td class="text-right">Price</td>
 </tr>
 </thead>
 <tbody>
 <tr ng-repeat="p in products | limitTo:limitVal">
 <td>{{p.name}}</td>
 <td>{{p.category}}</td>
 <td>{{p.expiry}}</td>
 <td class="text-right">{{p.price | currency }}</td>
 </tr>
 </tbody>
 </table>
 
 <table class="table table-striped table-bordered table-condensed">
 <thead>
 <tr>
 <td>Name</td>
 <td>Category</td>
 <td>Expiry</td>
 <td class="text-right">Price</td>
 </tr>
 </thead>
 <tbody>
 <tr ng-repeat="p in products | filter:selectItems">
 <td>{{p.name}}</td>
 <td>{{p.category}}</td>
 <td>{{p.expiry}}</td>
 <td class="text-right">{{p.price | currency }}</td>
 </tr>
 </tbody>
 </table>
 
 <table class="table table-striped table-bordered table-condensed">
 <thead>
 <tr>
 <td>Name</td>
 <td>Category</td>
 <td>Expiry</td>
 <td class="text-right">Price</td>
 </tr>
 </thead>
 <tbody>
 <tr ng-repeat="p in products | orderBy:'-price'">
 
 </tbody>
 </table>
 </div>
 </div>
 </body>
 </html>
 
 | 
可以对orderBy使用一个数组,数组元素为属性名或函数名,用于依次进行排序。
| 1
 | orderBy: [myCustomSorter, '-price']
 | 
过滤器也可以串联起来,一般是用于集合,对单个数据使用串联过滤器没什么必要:
| 1
 | ng-repeat="p in products | orderBy:[myCustomSorter, '-price'] | limitTo: 5"
 | 
自定义过滤器
通过Module.filter能够自定义过滤器,创建一个按照自定义规则格式化数据的过滤器。
比如:
labelCase格式化一个字符串为首字母大写其他小写/首字母小写其他大写,
skip跳过一定数量的项,然后正常返回后面的值
take将limitTo和skip结合起来
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | angular.module("exampleApp").filter("labelCase", function () {
 return function (value, reverse) {
 if (angular.isString(value)) {
 var intermediate =  reverse ? value.toUpperCase() : value.toLowerCase();
 return (reverse ? intermediate[0].toLowerCase() :
 intermediate[0].toUpperCase()) + intermediate.substr(1);
 } else {
 return value;
 }
 }
 })
 .filter("skip", function () {
 return function (data, count) {
 if (angular.isArray(data) && angular.isNumber(count)) {
 if (count > data.length || count < 1) {
 return data;
 } else {
 return data.slice(count);
 }
 } else {
 return data;
 }
 }
 })
 .filter("take", function ($filter) {
 return function (data, skipCount, takeCount) {
 var skippedData = $filter("skip")(data, skipCount);
 return $filter("limitTo")(skippedData, takeCount);
 }
 });
 
 | 
使用:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | <tr ng-repeat="p in products | orderBy:[myCustomSorter, '-price'] | limitTo: 5">
 <td>{{p.name | labelCase }}</td>
 <td>{{p.category | labelCase:true }}</td>
 <td>{{p.expiry}}</td>
 <td class="text-right">{{p.price | currency }}</td>
 </tr>
 
 ng-repeat="p in products | skip:2 | limitTo: 5"
 
 ng-repeat="p in products | take:2:5"
 
 |