# 四、过滤器

角度过滤器通常用于格式化模板绑定中的表达式。它们将输入数据转换成新的格式化数据类型。

## 用货币过滤器格式化字符串

### 问题

您希望使用本地化的货币标签来格式化货币金额。

### 溶液

使用内置的`currency`过滤器，并确保为用户的语言加载相应的区域设置文件:

```js
    <html>
    <head>
    <meta charset='utf-8'>
    <script src="js/angular.js"></script>
    <script src="js/angular-locale_de.js"></script>
    </head>
    <body ng-app>
    <input type="text" ng-model="amount" placeholder="Enter amount"/>
    <p>Default Currency: {{ amount | currency }}</p>
    <p>Custom Currency: {{ amount | currency: "Euro" }}</p>
    </body>
    </html>

```

输入一个数量，它将使用 Angular 的默认区域显示。

你可以在 [GitHub](https://github.com/fdietz/recipes-with-angular-js-examples/tree/master/chapter4/recipe1) 上找到完整的例子。

### 讨论

在我们的示例中，我们显式加载了德语区域设置，因此，默认格式将是德语。默认情况下，英语语言环境是附带的，因此不需要包含 angular-locale_en.js 文件。如果删除脚本标签，您将看到格式改为英语。这意味着，为了使本地化的应用程序正常工作，您需要加载相应的区域设置文件。所有可用的语言环境文件都可以在 [GitHub](https://github.com/angular/angular.js/tree/master/src/ngLocale) 上看到。

## 实现自定义过滤器以恢复输入字符串

### 问题

您希望恢复用户的文本输入。

### 溶液

实现一个自定义过滤器，它可以还原输入:

```js
    <body ng-app="MyApp">
    <input type="text" ng-model="text" placeholder="Enter text"/>
    <p>Input: {{ text }}</p>
    <p>Filtered input: {{ text | reverse }}</p>
    </body>

    var app = angular.module("MyApp", []);

    app.filter("reverse", function() {
    return function(input) {
    var result = "";
    input = input || "";
    for (var i=0; i<input.length; i++) {
    result = input.charAt(i) + result;
    }
    return result;
    };
    });

```

你可以在 [GitHub](https://github.com/fdietz/recipes-with-angular-js-examples/tree/master/chapter4/recipe2) 上找到完整的例子。

### 讨论

Angular 的过滤器函数需要一个过滤器名称和一个函数作为参数。该函数必须返回实现业务逻辑的实际过滤器函数。在这个例子中，它只有一个`input`参数。`for`循环反转输入后，将返回结果。

## 将配置参数传递给过滤器

### 问题

您希望通过引入配置参数来定制您的过滤器。

### 溶液

角度过滤器可以作为参数的散列传递，可以在过滤器函数中直接访问:

```js
    <body ng-app="MyApp">
    <input type="text" ng-model="text" placeholder="Enter text"/>
    <p>Input: {{ text }}</p>
    <p>Filtered input: {{ text | reverse: { suffix: "!"} }}</p>
    </body>

    var app = angular.module("MyApp", []);

    app.filter("reverse", function() {
    return function(input, options) {
    input = input || "";
    var result = "";
    var suffix = options["suffix"] || "";

    for (var i=0; i<input.length; i++) {
    result = input.charAt(i) + result;
    }

    if (input.length > 0) result += suffix;

    return result;
    };
    });

```

你可以在 [GitHub](https://github.com/fdietz/recipes-with-angular-js-examples/tree/master/chapter4/recipe3) 上找到完整的例子。

### 讨论

后缀`!`作为一个选项传递给过滤器功能，并附加到输出中。请注意，我们检查是否存在实际输入，因为我们不想在没有任何输入的情况下呈现后缀。

## 过滤 DOM 节点列表

### 问题

您希望过滤名称列表。

### 溶液

除了字符串作为输入，Angular 的过滤器还可以处理数组:

```js
    <body ng-app="MyApp">
    <ul ng-init="names = ['Peter', 'Anton', 'John']">
    <li ng-repeat="name in names | exclude:'Peter' ">
    <span>{{name}}</span>
    </li>
    </ul>
    </body>

    var app = angular.module("MyApp", []);

    app.filter("exclude", function() {
    return function(input, exclude) {
    var result = [];
    for (var i=0; i<input.length; i++) {
    if (input[i] !== exclude) {
    result.push(input[i]);
    }
    }

    return result;
    };
    });

```

我们将`Peter`作为单个参数传递给排除过滤器，该过滤器将渲染除`Peter`之外的所有名称。

你可以在 [GitHub](https://github.com/fdietz/recipes-with-angular-js-examples/tree/master/chapter4/recipe4) 上找到完整的例子。

### 讨论

过滤器实现遍历所有名称，并创建一个结果数组，不包括“Peter”。请注意，过滤器函数的实际语法与我们前面的字符串输入示例完全没有变化。

## 将过滤器链接在一起

### 问题

您希望将几个过滤器组合成一个结果。

### 溶液

过滤器可以使用类似 Unix 的管道语法进行链接:

```js
    <body ng-app="MyApp">
    <ul ng-init="names = ['Peter', 'Anton', 'John']">
    <li ng-repeat="name in names | exclude:'Peter' | sortAscending ">
    <span>{{name}}</span>
    </li>
    </ul>
    </body>

```

### 讨论

管道符号(`|`)用于将多个过滤器链接在一起。首先，我们将从名字的初始数组开始。应用`exclude`过滤器后，数组只包含`['Anton', 'John']`，然后我们将按升序对名称进行排序。

我把`sortAscending`过滤器的实现作为一个练习留给读者。

## 测试过滤器

### 问题

您希望对新过滤器进行单元测试。让我们从一个简单的过滤器开始，它根据布尔值呈现一个复选标记:

```js
    <body ng-init="data = true">
    <p>{{ data | checkmark}}</p>
    <p>{{ !data | checkmark}}</p>
    </body>

    var app = angular.module("MyApp", []);

    app.filter('checkmark', function() {
    return function(input) {
    return input ? '\u2713' : '\u2718';
    };
    });

```

### 溶液

再次使用角种子项目作为引导:

```js
    describe('MyApp Tabs', function() {
    beforeEach(module('MyApp'));

    describe('checkmark', function() {
    it('should convert boolean values to unicode checkmark or cross',
    inject(function(checkmarkFilter) {
    expect(checkmarkFilter(true)).toBe('\u2713');
    expect(checkmarkFilter(false)).toBe('\u2718');
    }));
    });
    });

```

### 讨论

`beforeEach`加载模块，`it`方法为我们注入过滤功能。注意必须叫`checkmarkFilter;`否则 Angular 无法正确注入我们的滤镜功能。