2016-05-13 16:44:14 -04:00
block includes
include ../_util-fns
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
2015-11-10 13:31:46 -05:00
Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket.
2016-05-27 05:40:44 -04:00
每个应用开始的时候差不多都是一些简单任务:获取数据、转换它们,然后把它们显示给用户。
获取数据可能简单到创建一个局部变量就行, 也可能复杂到从WebSocket中获取数据流。
2016-05-13 16:44:14 -04:00
Once data arrive, we could push their raw `toString` values directly to the view.
2015-11-10 13:31:46 -05:00
That rarely makes for a good user experience.
2016-05-13 16:44:14 -04:00
E.g., almost everyone prefers a simple birthday date like
<samp>April 15, 1988</samp> to the original raw string format
— <samp>Fri Apr 15 1988 00:00:00 GMT-0700 (Pacific Daylight Time)</samp>.
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
一旦取到数据,我们可以把它们原始值的`toString`结果直接推入视图中。
但这种做法很少能具备良好的用户体验。
比如,几乎每个人都更喜欢简单的日期格式,例如<samp>1988-04-15</samp>,而不是服务端传过来的原始字符串格
式 —— <samp>Fri Apr 15 1988 00:00:00 GMT-0700 (Pacific Daylight Time)</samp>。
2015-10-19 12:56:24 -04:00
Clearly some values benefit from a bit of massage. We soon discover that we
desire many of the same transformations repeatedly, both within and across many applications.
2015-11-10 13:31:46 -05:00
We almost think of them as styles.
2015-10-19 12:56:24 -04:00
In fact, we'd like to apply them in our HTML templates as we do styles.
2016-05-27 05:40:44 -04:00
显然,对某些值做一点修饰会显得更友好。我们很快就会发现,相同的“数据转换”工作要重复做很多次,甚至会出现在很多应用中。
我们甚至可以把它看做样式。
事实上, 我们确实更喜欢像样式那样把它们应用到HTML模板中。
2016-05-13 16:44:14 -04:00
p.
2015-11-10 13:31:46 -05:00
Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML!
2016-05-20 19:18:58 -04:00
Try the #[+liveExampleLink2()].
2015-10-19 12:56:24 -04:00
2016-05-27 05:40:44 -04:00
p.
欢迎来到Angular“管道(Pipe)”的世界! 我们可以把这种简单的“显示值”转换器声明在HTML中。
试试#[+liveExampleLink2('在线例子')].
2015-10-19 12:56:24 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
## Using Pipes
2016-05-27 05:40:44 -04:00
## 使用管道
2015-10-19 12:56:24 -04:00
2015-11-10 13:31:46 -05:00
A pipe takes in data as input and transforms it to a desired output.
We'll illustrate by transforming a component's birthday property into
2015-12-13 01:01:46 -05:00
a human-friendly date:
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
管道把数据作为输入,然后转换它,给出期望的输出。
我们将把组件的`birthday`属性转换成对人类更友好的日期格式,来说明这一点:
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/hero-birthday1.component.ts', null, 'app/hero-birthday1.component.ts')(format='.')
2015-11-02 03:28:38 -05:00
2015-11-10 13:31:46 -05:00
:marked
2016-04-06 14:15:07 -04:00
Focus on the component's template.
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
重点看下组件的模板。
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/app.component.html', 'hero-birthday-template')(format=".")
2016-05-13 16:44:14 -04:00
2015-11-10 13:31:46 -05:00
:marked
2015-12-13 01:01:46 -05:00
Inside the interpolation expression we flow the component's `birthday` value through the
2016-04-06 14:15:07 -04:00
[pipe operator](./template-syntax.html#pipe) ( | ) to the [Date pipe](../api/common/DatePipe-class.html)
2015-12-13 01:01:46 -05:00
function on the right. All pipes work this way.
2015-10-19 12:56:24 -04:00
2016-05-27 05:40:44 -04:00
在这个插值表达式中,我们让组件的`birthday`值通过[管道操作符](./template-syntax.html#pipe)( | )流动到
右侧的[Date管道](../api/common/DatePipe-class.html)函数中。所有管道都会用这种方式工作。
2015-10-19 12:56:24 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
## Built-in pipes
2016-05-27 05:40:44 -04:00
## 内建的管道
2016-05-13 16:44:14 -04:00
Angular comes with a stock of pipes such as
2015-10-19 12:56:24 -04:00
`DatePipe`, `UpperCasePipe`, `LowerCasePipe`, `CurrencyPipe`, and `PercentPipe`.
They are all immediately available for use in any template.
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
Angular内置了一些管道, 比如`DatePipe`、`UpperCasePipe`、`LowerCasePipe`、`CurrencyPipe`和`PercentPipe`。
它们全都可以直接用在任何模板中。
2015-10-19 12:56:24 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-13 17:00:43 -05:00
Learn more about these and many other built-in pipes in the the [API Reference](../api/#!?apiFilter=pipe);
2015-11-10 13:31:46 -05:00
filter for entries that include the word "pipe".
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
要学习更多内建管道的知识,参见[API参考](../api/#!?apiFilter=pipe), 并用“pipe”为关键词对结果进行过滤。
2016-05-13 16:44:14 -04:00
Angular 2 doesn't have a `FilterPipe` or an `OrderByPipe` for reasons explained in an [appendix below](#no-filter-pipe).
2015-10-19 12:56:24 -04:00
2016-05-27 05:40:44 -04:00
Angular 2没有`FilterPipe`或`OrderByPipe`管道,原因在[后面的附录中](#no-filter-pipe)有解释。
2015-10-19 12:56:24 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
## Parameterizing a Pipe
2016-05-27 05:40:44 -04:00
## 对管道进行参数化
2015-11-10 13:31:46 -05:00
2016-05-13 16:44:14 -04:00
A pipe may accept any number of optional parameters to fine-tune its output.
2015-10-19 12:56:24 -04:00
We add parameters to a pipe by following the pipe name with a colon ( : ) and then the parameter value
2015-10-23 12:31:51 -04:00
(e.g., `currency:'EUR'`). If our pipe accepts multiple parameters, we separate the values with colons (e.g. `slice:1:5`)
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
管道可能接受任何数量的可选参数来对它的输出进行微调。
我们可以在管道名后面添加一个冒号( : )再跟一个参数值,来为管道添加参数(比如`currency:'EUR'`)。
如果我们的管道可以接受多个参数,那么就用冒号来分隔这些参数值(比如`slice:1:5`)。
2015-12-13 01:01:46 -05:00
We'll modify our birthday template to give the date pipe a format parameter.
2016-05-13 16:44:14 -04:00
After formatting the hero's April 15th birthday, it should render as **<samp>04/15/88</samp>**.
2015-10-19 12:56:24 -04:00
2016-05-27 05:40:44 -04:00
我们将通过修改生日模板来给这个日期管道提供一个格式化参数。
当格式化完该英雄的4月15日生日之后, 它应该被渲染成**<samp>04/15/88</samp>**。
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/app.component.html', 'format-birthday')(format=".")
2015-10-19 12:56:24 -04:00
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
The parameter value can be any valid
2016-02-12 09:54:42 -05:00
[template expression](./template-syntax.html#template-expressions)
2016-04-06 14:15:07 -04:00
such as a string literal or a component property.
2015-12-13 01:01:46 -05:00
In other words, we can control the format through a binding the same way we control the birthday value through a binding.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
参数值可以是任何有效的[模板表达式](./template-syntax.html#template-expressions),比如字符串字面量或组件的属性。
换句话说,借助属性绑定,我们也可以像用绑定来控制生日的值一样,控制生日的显示格式。
2015-12-13 01:01:46 -05:00
Let's write a second component that *binds* the pipe's format parameter
to the component's `format` property. Here's the template for that component:
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
我们来写第二个组件,它把管道的格式参数*绑定*到该组件的`format`属性。这里是新组件的模板:
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/hero-birthday2.component.ts', 'template', 'app/hero-birthday2.component.ts (template)')(format=".")
2016-05-13 16:44:14 -04:00
2015-11-10 13:31:46 -05:00
:marked
2016-05-13 16:44:14 -04:00
We also added a button to the template and bound its click event to the component's `toggleFormat()` method.
2015-10-19 12:56:24 -04:00
That method toggles the component's `format` property between a short form
2016-05-13 16:44:14 -04:00
(`'shortDate'`) and a longer form (`'fullDate'`).
2016-05-27 05:40:44 -04:00
我们还能把一个按钮添加到模板中,并把它的点击事件绑定到组件的`toggleFormat()`方法。
此方法会在短日期格式(`'shortDate'`)和长日期格式(`'fullDate'`)之间切换组件的`format`属性。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/hero-birthday2.component.ts', 'class', 'app/hero-birthday2.component.ts (class)')(format='.')
2016-05-13 16:44:14 -04:00
2015-12-13 01:01:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
As we click the button, the displayed date alternates between
2016-05-13 16:44:14 -04:00
"**<samp>04/15/1988</samp>**" and
"**<samp>Friday, April 15, 1988</samp>**".
2015-11-02 03:28:38 -05:00
2016-05-27 05:40:44 -04:00
当我们点击按钮的时候,显示的日志会在"**<samp>04/15/1988</samp>**"和"**<samp>Friday, April 15, 1988</samp>**"之间切换。
2015-11-02 03:28:38 -05:00
figure.image-display
img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle")
2015-11-10 13:31:46 -05:00
:marked
2015-12-13 01:01:46 -05:00
2015-10-19 12:56:24 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
2016-03-11 02:24:28 -05:00
Learn more about the `DatePipes` format options in the [API Docs](../api/common/DatePipe-class.html).
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
要了解更多`DatePipes`的格式选项,请参阅[API文档](../api/common/DatePipe-class.html)。
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
## Chaining pipes
2016-05-27 05:40:44 -04:00
## 链式管道
2016-05-13 16:44:14 -04:00
2015-11-10 13:31:46 -05:00
We can chain pipes together in potentially useful combinations.
2015-10-19 12:56:24 -04:00
In the following example, we chain the birthday to the `DatePipe` and on to the `UpperCasePipe`
2015-11-10 13:31:46 -05:00
so we can display the birthday in uppercase. The following birthday displays as
2016-05-13 16:44:14 -04:00
**<samp>APR 15, 1988</samp>**
2015-11-02 03:28:38 -05:00
2016-05-27 05:40:44 -04:00
我们可以把管道链在一起,以组合出一些潜在的有用功能。
下面这个例子中,我们把`birthday`链到`DatePipe`管道,然后又链到`UpperCasePipe`,这样我们就可以把生日显示成大写形式了。
比如下面的代码就会把生日显示成**<samp>APR 15, 1988</samp>**:
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/app.component.html', 'chained-birthday')(format=".")
2015-11-02 03:28:38 -05:00
2015-11-10 13:31:46 -05:00
:marked
2016-05-13 16:44:14 -04:00
This example — which displays **<samp>FRIDAY, APRIL 15, 1988</samp>** —
chains the same pipes as above, but passes in a parameter to `date` as well.
2015-11-02 03:28:38 -05:00
2016-05-27 05:40:44 -04:00
下面这个显示**<samp>FRIDAY, APRIL 15, 1988</samp>**的例子用同样的方式链接了这两个管道,而且同时还给`date`管道传进去一个参数。
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/app.component.html', 'chained-parameter-birthday')(format=".")
2015-10-19 12:56:24 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
## Custom Pipes
2016-05-27 05:40:44 -04:00
## 自定义管道
2015-10-19 12:56:24 -04:00
2015-11-02 03:28:38 -05:00
We can write our own custom pipes.
2015-12-13 01:01:46 -05:00
Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers:
2015-10-19 12:56:24 -04:00
2016-05-27 05:40:44 -04:00
我们还可以写自己的自定义管道。
下面就是一个名叫`ExponentialStrengthPipe`的管道,它可以放大英雄的能力:
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/exponential-strength.pipe.ts', null, 'app/exponential-strength.pipe.ts')(format=".")
2016-05-13 16:44:14 -04:00
2015-11-10 13:31:46 -05:00
:marked
2015-11-21 21:05:50 -05:00
This pipe definition reveals several key points
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
在这个管道的定义中体现了几个关键点:
2015-12-13 01:01:46 -05:00
* A pipe is a class decorated with pipe metadata.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
* 管道是一个带有“管道元数据(pipe metadata)”装饰器的类。
2015-12-28 14:52:41 -05:00
* The pipe class implements the `PipeTransform` interface's `transform` method that
2016-04-27 09:45:21 -04:00
accepts an input value followed by optional parameters and returns the transformed value.
2015-12-13 01:01:46 -05:00
2016-05-27 05:40:44 -04:00
* 这个管道类实现了`PipeTransform`接口的`transform`方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。
2016-04-27 09:45:21 -04:00
* There will be one additional argument to the `transform` method for each parameter passed to the pipe.
2016-05-13 16:44:14 -04:00
Our pipe has one such parameter: the `exponent`.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
* 当每个输入值被传给`transform`方法时,还会带有一个额外的参数,比如我们这个管道中的`exponent`(放大指数)。
2015-12-13 01:01:46 -05:00
* We tell Angular that this is a pipe by applying the
2016-05-13 16:44:14 -04:00
`@Pipe` #{_decorator} which we import from the core Angular library.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
* 我们通过`@Pipe`#{_decoratorCn}告诉Angular: 这是一个管道。该#{_decoratorCn}是从Angular的`core`库中引入的。
2016-05-13 16:44:14 -04:00
* The `@Pipe` #{_decorator} allows us to define the
pipe name that we'll use within template expressions. It must be a valid JavaScript identifier.
2016-01-15 15:30:00 -05:00
Our pipe's name is `exponentialStrength`.
2015-12-13 01:01:46 -05:00
2016-05-27 05:40:44 -04:00
* 这个`@Pipe`#{_decoratorCn}允许我们定义管道的名字, 这个名字会被用在模板表达式中。它必须是一个有效的JavaScript标识符。
比如,我们这个管道的名字是`exponentialStrength`。
2015-12-28 14:52:41 -05:00
.l-sub-section
:marked
### The *PipeTransform* Interface
2016-05-27 05:40:44 -04:00
### *PipeTransform*接口
2015-12-13 01:01:46 -05:00
2016-04-06 14:15:07 -04:00
The `transform` method is essential to a pipe.
2016-01-13 17:00:43 -05:00
The `PipeTransform` *interface* defines that method and guides both tooling and the compiler.
It is technically optional; Angular looks for and executes the `transform` method regardless.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
`transform`方法是管道的基本要素。
`PipeTransform`*接口*中定义了它,并用它指导各种工具和编译器。
从技术角度看, 它是可选的。Angular不会管它, 而是直接查找并执行`transform`方法。
2015-12-28 14:52:41 -05:00
:marked
2015-12-13 01:01:46 -05:00
Now we need a component to demonstrate our pipe.
2016-05-27 05:40:44 -04:00
现在,我们需要一个组件来演示这个管道。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/power-booster.component.ts',null,'app/power-booster.component.ts')(format='.')
2015-11-02 03:28:38 -05:00
figure.image-display
img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster")
2015-10-17 13:01:41 -04:00
2015-11-10 13:31:46 -05:00
:marked
2015-10-23 12:31:51 -04:00
Two things to note:
2016-05-27 05:40:44 -04:00
要注意的有两点:
2015-12-13 01:01:46 -05:00
1. We use our custom pipe the same way we use the built-in pipes.
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
1. 我们使用自定义管道的方式和内建管道完全相同。
2016-05-13 16:44:14 -04:00
1. We must include our pipe in the `pipes` #{_array} of the `@Component` #{_decorator}.
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
1. 我们必须在`@Component`#{_decoratorCn}的`pipes`数组中包含这个管道。
2015-12-13 01:01:46 -05:00
.callout.is-helpful
2016-05-13 16:44:14 -04:00
header Remember the pipes #{_array}!
2016-05-27 05:40:44 -04:00
header 记住`pipes`数组
2015-11-10 13:31:46 -05:00
:marked
Angular reports an error if we neglect to list our custom pipe.
2015-10-19 12:56:24 -04:00
We didn't list the `DatePipe` in our previous example because all
2015-11-10 13:31:46 -05:00
Angular built-in pipes are pre-registered.
2015-10-19 12:56:24 -04:00
Custom pipes must be registered manually.
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
如果我们忘了列出自定义管道, Angular会报告一个错误。
我们不用在以前的例子中列出`DatePipe`, 是因为所有的Angular内建管道都被预先注册过了。
而自定义管道就必须被手动注册。
2016-05-13 16:44:14 -04:00
p.
2016-05-20 19:18:58 -04:00
If we try the #[+liveExampleLink()],
2015-10-19 12:56:24 -04:00
we can probe its behavior by changing the value and the optional exponent in the template.
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
p.
试试这个#[+liveExampleLink()],然后在模板中修改能量值和可选的放大指数,就能看懂它的行为方式。
2016-05-13 16:44:14 -04:00
:marked
2015-10-19 12:56:24 -04:00
## Power Boost Calculator (extra-credit)
2016-05-27 05:40:44 -04:00
## 能力倍增计算器(加分项)
2016-05-13 16:44:14 -04:00
2015-10-19 12:56:24 -04:00
It's not much fun updating the template to test our custom pipe.
We could upgrade the example to a "Power Boost Calculator" that combines
2015-12-13 01:01:46 -05:00
our pipe and two-way data binding with `ngModel`.
2015-10-19 12:56:24 -04:00
2016-05-27 05:40:44 -04:00
仅仅升级模板来测试这个自定义管道其实没多大意思。
我们干脆把这个例子升级为“能力倍增计算器”,它可以把该管道和使用`ngModel`的双向数据绑定组合起来。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/power-boost-calculator.component.ts', null, '/app/power-boost-calculator.component.ts')(format='.')
2015-11-02 03:28:38 -05:00
figure.image-display
2015-12-13 01:01:46 -05:00
img(src='/resources/images/devguide/pipes/power-boost-calculator-anim.gif' alt="Power Boost Calculator")
2015-10-19 12:56:24 -04:00
2015-10-17 13:01:41 -04:00
.l-main-section
2016-05-13 16:44:14 -04:00
a#change-detection
2016-01-13 17:00:43 -05:00
:marked
## Pipes and Change Detection
2016-05-27 05:40:44 -04:00
## 管道与变更检测
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
Angular looks for changes to data-bound values through a *change detection* process that runs after every JavaScript event:
2016-05-13 16:44:14 -04:00
every keystroke, mouse move, timer tick, and server response. This could be expensive.
2016-04-06 14:15:07 -04:00
Angular strives to lower the cost whenever possible and appropriate.
2016-05-27 05:40:44 -04:00
Angular通过*变更检测*过程来查找绑定值的更改, 并在每一次JavaScript事件之后运行: 每次按键、鼠标移动、定时器以及服务器的响应。
这可能会让变更检测显得很昂贵, 但是Angular会尽可能降低变更检测的成本。
2016-01-13 17:00:43 -05:00
Angular picks a simpler, faster change detection algorithm when we use a pipe. Let's see how.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
当我们使用管道时, Angular选用了一种简单、快速的变更检测算法。
2016-04-06 14:15:07 -04:00
### No pipe
2016-05-27 05:40:44 -04:00
### 无管道
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
The component in our next example uses the default, aggressive change detection strategy to monitor and update
2016-05-13 16:44:14 -04:00
its display of every hero in the `heroes` #{_array}. Here's the template:
2016-05-27 05:40:44 -04:00
我们下一个例子中的组件使用默认的、激进(昂贵)的变更检测策略来检测和更新`heroes`数组中的每个英雄。下面是它的模板:
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-1', 'app/flying-heroes.component.html (v1)')(format='.')
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
:marked
2016-05-13 16:44:14 -04:00
The companion component class provides heroes, adds new heroes into the #{_array}, and can reset the #{_array}.
2016-05-27 05:40:44 -04:00
和模板相伴的组件类可以提供英雄数组,能把新的英雄添加到数组中,还能重置英雄数组。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'v1', 'app/flying-heroes.component.ts (v1)')(format='.')
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
:marked
2016-04-06 14:15:07 -04:00
We can add a new hero and Angular updates the display when we do.
2016-05-13 16:44:14 -04:00
The `reset` button replaces `heroes` with a new #{_array} of the original heroes and Angular updates the display when we do.
If we added the ability to remove or change a hero, Angular would detect those changes too and update the display as well.
2016-01-13 17:00:43 -05:00
2016-05-27 05:40:44 -04:00
我们可以添加新的英雄, 加完之后, Angular就会更新显示。
`reset`按钮会把`heroes`替换成一个由原来的英雄组成的新数组, 重置完之后, Angular就会更新显示。
如果我们提供了删除或修改英雄的能力, Angular也会检测到那些更改, 并更新显示。
2016-04-06 14:15:07 -04:00
### Flying Heroes pipe
2016-05-27 05:40:44 -04:00
### “会飞的英雄”管道
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
Let's add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
2016-05-27 05:40:44 -04:00
我们来往`*ngFor`重复器中添加一个`FlyingHeroesPipe`管道,这个管道能过滤出所有会飞的英雄。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-flying-heroes', 'app/flying-heroes.component.html (flyers)')(format='.')
2015-11-10 13:31:46 -05:00
:marked
2016-01-13 17:00:43 -05:00
Here's the `FlyingHeroesPipe` implementation which follows the pattern for custom pipes we saw earlier.
2016-05-27 05:40:44 -04:00
下面是`FlyingHeroesPipe`的实现,它遵循了我们以前见过的那些写自定义管道的模式。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.pipe.ts', 'pure', 'app/flying-heroes.pipe.ts')(format='.')
2015-10-19 12:56:24 -04:00
2016-05-20 19:18:58 -04:00
p.
When we run the sample now we see odd behavior (try it in the #[+liveExampleLink()]).
2016-04-06 14:15:07 -04:00
Every hero we add is a flying hero but none of them are displayed.
2016-05-27 05:40:44 -04:00
p.
如果我们现在就运行这个例子,我们会看到一些古怪的行为(在#[+liveExampleLink()]中试试)。
我们添加的每个英雄都会飞,但他们一个都没有显示出来。
2016-05-20 19:18:58 -04:00
:marked
2016-04-06 14:15:07 -04:00
Although we're not getting the behavior we want, Angular isn't broken.
2016-01-13 17:00:43 -05:00
It's just using a different change detection algorithm — one that ignores changes to the list or any of its items.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
虽然我们没有得到期望的行为, 但Angular也没有出错。
这里只是用了另一种变更检测算法 —— 它会忽略对列表及其子项所做的任何更改。
2016-01-13 17:00:43 -05:00
Look at how we're adding a new hero:
2016-05-27 05:40:44 -04:00
来看看我们是如何添加新英雄的:
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'push')(format='.')
:marked
2016-05-13 16:44:14 -04:00
We're adding the new hero into the `heroes` #{_array}. The reference to the #{_array} hasn't changed.
It's the same #{_array}. That's all Angular cares about. From its perspective, *same #{_array}, no change, no display update*.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
当我们往`heroes`数组中添加一个新的英雄时, 这个数组的引用并没有改变。它还是那个数组。而引用却是Angular所关心的一切。
从Angular的角度来看, *这是同一个数组,没有变化,也就不需要更新显示*。
2016-05-13 16:44:14 -04:00
We can fix that. Let's create a new #{_array} with the new hero appended and assign that to `heroes`.
This time Angular detects that the #{_array} reference has changed.
It executes the pipe and updates the display with the new #{_array} which includes the new flying hero.
2016-01-13 17:00:43 -05:00
2016-05-27 05:40:44 -04:00
我们可以修复它。让我们创建一个新数组,把这个英雄追加进去,并把它赋给`heroes`。
这次, Angular检测到数组的引用变化了。它执行了这个管道, 并使用这个新数组更新显示, 这次它就包括新的飞行英雄了。
2016-05-13 16:44:14 -04:00
*If we **mutate** the #{_array}, no pipe is invoked and no display updated;
if we **replace** the #{_array}, then the pipe executes and the display is updated*.
2016-05-20 19:18:58 -04:00
The *Flying Heroes* extends the
2016-01-13 17:00:43 -05:00
code with checkbox switches and additional displays to help us experience these effects.
2016-05-13 16:44:14 -04:00
2016-05-27 05:40:44 -04:00
*如果我们**修改了**这个数组,不会执行任何管道,显示也没有更新。
如果我们**替换了**这个数组,管道就会被执行,显示也更新了。*
这个*飞行英雄*的例子用检查框和额外的显示内容扩展了原有代码,来帮我们体验这些效果。
2016-01-13 17:00:43 -05:00
figure.image-display
img(src='/resources/images/devguide/pipes/flying-heroes-anim.gif' alt="Flying Heroes")
2015-11-10 13:31:46 -05:00
2016-01-13 17:00:43 -05:00
:marked
2016-05-13 16:44:14 -04:00
Replacing the #{_array} is an efficient way to signal to Angular that it should update the display.
When do we replace the #{_array}? When the data change.
2016-01-13 17:00:43 -05:00
That's an easy rule to follow in *this toy* example
where the only way to change the data is by adding a new hero.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
直接替换这个数组是通知Angular更新显示的一种高效方式。
我们该什么时候替换这个数组呢?当数据变化的时候。
在这个*玩具级*例子中,这是一个简单的规则,因为这里修改数据的唯一途径就是添加新英雄。
2016-04-06 14:15:07 -04:00
More often we don't know when the data have changed,
especially in applications that mutate data in many ways,
2016-01-13 17:00:43 -05:00
perhaps in application locations far away.
A component is such an application usually can't know about those changes.
Moreover, it's unwise to distort our component design to accommodate a pipe.
We strive as much as possible to keep the component class independent of the HTML.
The component should be unaware of pipes.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
更多情况下,我们不知道什么时候数据变化了,尤其是在那些有很多种途径改动数据的程序中 —— 可能在程序中很远的地方。
组件就是一个通常无法知道那些改动的例子。此外,它会导致削足适履 —— 扭曲我们的组件设计来适应管道。
我们要尽可能保持组件类独立于HTML。组件不应该关心管道的存在。
2016-01-13 17:00:43 -05:00
Perhaps we should consider a different kind of pipe for filtering flying heroes, an *impure pipe*.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
也行我们可以考虑用另一种管道来过滤会飞的英雄了,一个*非纯(impure)管道*。
2016-01-13 17:00:43 -05:00
.l-main-section
:marked
## Pure and Impure Pipes
2016-05-27 05:40:44 -04:00
## 纯(pure)管道与非纯(impure)管道
2015-11-10 13:31:46 -05:00
2016-01-13 17:00:43 -05:00
There are two categories of pipes: **pure** and **impure**.
2016-05-13 16:44:14 -04:00
Pipes are pure by default. Every pipe we've seen so far has been pure.
2016-01-13 17:00:43 -05:00
We make a pipe impure by setting its pure flag to false. We could make the `FlyingHeroesPipe`
2016-05-13 16:44:14 -04:00
impure like this:
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
有两类管道:**纯**的与**非纯**的。
默认情况下,管道都是纯的。我们以前见到的每个管道都是纯的。
通过把它的`pure`标志设置为`false`,我们可以制作一个非纯管道。我们可以像这样让`FlyingHeroesPipe`变成非纯的:
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.pipe.ts', 'pipe-decorator')(format='.')
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
:marked
Before we do that, let's understand the difference between *pure* and *impure*, starting with a *pure* pipe.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
在继续往下走之前,我们先理解一下*纯*和*非纯*之间的区别,从*纯*管道开始。
2016-01-13 17:00:43 -05:00
### Pure pipes
2016-05-27 05:40:44 -04:00
### 纯管道
2016-04-06 14:15:07 -04:00
2016-05-13 16:44:14 -04:00
block pure-change
:marked
Angular executes a *pure pipe* only when it detects a *pure change* to the input value.
A ***pure change*** is *either* a change to a primitive input value (`String`, `Number`, `Boolean`, `Symbol`)
*or* a changed object reference (`Date`, `Array`, `Function`, `Object`).
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
Angular只有在它检测到输入值发生了*纯变更*时才会执行*纯管道*。
***纯变更***是指对原始类型值(`String`、`Number`、`Boolean`、`Symbol`)的更改,
或者对对象引用(`Date`、`Array`、`Function`、`Object`)的更改。
2016-05-13 16:44:14 -04:00
:marked
Angular ignores changes *within* (composite) objects.
It won't call a pure pipe if we change an input month, add to an input #{_array}, or update an input object property.
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
Angular会忽略(复合)对象*内部*的更改。
如果我们更改了输入日期(`Date`)中的月份、往一个输入数组(`Array`)中添加新值或者更新了一个输入对象(`Object`)的属性, Angular都不会调用纯管道。
2016-04-06 14:15:07 -04:00
This may seem restrictive but is is also fast.
2016-05-13 16:44:14 -04:00
An object reference check is fast — much faster than a deep check for
differences — so Angular can quickly determine if it can skip both the
pipe execution and a view update.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
这可能看起来是一种限制,但它保证了速度。
对象引用的检查是非常快的( 比递归的深检查要快得多) , 所以Angular可以快速的决定是否应该在执行管道和更新视图时跳过它。
2016-01-13 17:00:43 -05:00
For this reason, we prefer a pure pipe if we can live with the change detection strategy.
When we can't, we *may* turn to the impure pipe.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
因此,如果我们要和变更检测策略打交道,就会更喜欢用纯管道。
如果不能,我们就*可以*转回到非纯管道。
2016-01-13 17:00:43 -05:00
.l-sub-section
:marked
2016-04-06 14:15:07 -04:00
Or we might not use a pipe at all.
2016-01-13 17:00:43 -05:00
It may be better to pursue the pipe's purpose with a property of the component,
a point we take up later.
2016-05-27 05:40:44 -04:00
或者我们也可以完全不用管道。
有时候,使用组件的属性能比用管道更好的达到目的,这一点我们等后面会再提起。
2016-01-13 17:00:43 -05:00
:marked
### Impure pipes
2016-05-27 05:40:44 -04:00
### 非纯管道
2016-05-13 16:44:14 -04:00
2016-04-06 14:15:07 -04:00
Angular executes an *impure pipe* during *every* component change detection cycle.
2016-01-13 17:00:43 -05:00
An impure pipe will be called a lot, as often as every keystroke or mouse-move.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
Angular会在每个组件的变更检测周期中执行*非纯管道*。
非纯管道可能会被调用很多次,和每个按键或每次鼠标移动一样频繁。
2016-04-06 14:15:07 -04:00
With that concern in mind, we must implement an impure pipe with great care.
2016-01-13 17:00:43 -05:00
An expensive, long-running pipe could destroy the user experience.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
要在脑子里绷着这根弦,我们必须小心翼翼的实现非纯管道。
一个昂贵、迟钝的管道将摧毁用户体验。
2016-01-13 17:00:43 -05:00
<a id="impure-flying-heroes"></a>
### An impure *FlyingHeroesPipe*
2016-05-27 05:40:44 -04:00
### 非纯版本的*FlyingHeroesPipe*
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
A flip of the switch turns our `FlyingHeroesPipe` into a `FlyingHeroesImpurePipe`.
Here's the complete implementation:
2016-05-27 05:40:44 -04:00
我们把`FlyingHeroesPipe`换成了`FlyingHeroesImpurePipe`。
下面是完整的实现:
2016-01-13 17:00:43 -05:00
+makeTabs(
2016-04-06 14:15:07 -04:00
'pipes/ts/app/flying-heroes.pipe.ts, pipes/ts/app/flying-heroes.pipe.ts',
2016-01-13 17:00:43 -05:00
'impure, pure',
'FlyingHeroesImpurePipe, FlyingHeroesPipe')(format='.')
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
:marked
We inherit from `FlyingHeroesPipe` to prove the point that nothing changed internally.
The only difference is the `pure` flag in the pipe metadata.
2016-04-06 14:15:07 -04:00
2016-05-27 05:40:44 -04:00
我们把它从`FlyingHeroesPipe`中继承下来,以证明无需改动内部代码。
唯一的区别是管道元数据中的`pure`标志。
2016-01-13 17:00:43 -05:00
This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
2016-05-27 05:40:44 -04:00
这是一个很好地非纯管道候选者,因为它的`transform`函数又小又快。
2016-01-13 17:00:43 -05:00
+makeExample('pipes/ts/app/flying-heroes.pipe.ts','filter')(format='.')
2015-10-19 12:56:24 -04:00
2016-01-13 17:00:43 -05:00
We can derive a `FlyingHeroesImpureComponent` that we derive from the `FlyingHeroesComponent`.
2016-05-27 05:40:44 -04:00
我们可以从`FlyingHeroesComponent`派生出一个`FlyingHeroesImpureComponent`。
2016-03-26 12:18:13 -04:00
+makeExample('pipes/ts/app/flying-heroes.component.ts','impure-component','app/flying-heroes.component.ts (FlyingHeroesImpureComponent)')(format='.')
2016-05-20 19:18:58 -04:00
p.
2016-04-06 14:15:07 -04:00
The only substantive change is the pipe.
2016-05-20 19:18:58 -04:00
We can confirm in the #[+liveExampleLink()] that the #[i flying heroes]
display updates as we enter new heroes even when we mutate the
#[code heroes] #{_array}.
2016-05-27 05:40:44 -04:00
p.
唯一的重大改动就是管道。
我们可以在#[+liveExampleLink()]中确认,当我们输入新的英雄甚至修改#[code heroes]数组时,这个#[i 会飞的英雄]的显示也跟着更新了。
2016-05-13 16:44:14 -04:00
- var _dollar = _docsFor === 'ts' ? '$' : '';
2016-05-20 19:18:58 -04:00
h3#async-pipe The impure #[i AsyncPipe]
2016-05-27 05:40:44 -04:00
h3#async-pipe 非纯管道#[i AsyncPipe]
2016-05-13 16:44:14 -04:00
:marked
2016-01-13 17:00:43 -05:00
The Angular `AsyncPipe` is an interesting example of an impure pipe.
2016-05-13 16:44:14 -04:00
The `AsyncPipe` accepts a `#{_Promise}` or `#{_Observable}` as input
2016-01-13 17:00:43 -05:00
and subscribes to the input automatically, eventually returning the emitted value(s).
2015-11-10 13:31:46 -05:00
2016-05-27 05:40:44 -04:00
Angular的`AsyncPipe`是一个有趣的非纯管道的例子。
`AsyncPipe`接受一个`Promise`或`Observable`作为输入,并且自动订阅这个输入,最终返回它们给出的值。
2016-04-06 14:15:07 -04:00
It is also stateful.
2016-05-13 16:44:14 -04:00
The pipe maintains a subscription to the input `#{_Observable}` and
keeps delivering values from that `#{_Observable}` as they arrive.
2016-05-27 05:40:44 -04:00
In this next example, we bind an `#{_Observable}` of message strings
2016-05-13 16:44:14 -04:00
(`message#{_dollar}`) to a view with the `async` pipe.
2015-10-19 12:56:24 -04:00
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/hero-async-message.component.ts', null, 'app/hero-async-message.component.ts')
2015-10-19 12:56:24 -04:00
2015-11-10 13:31:46 -05:00
:marked
2015-10-19 12:56:24 -04:00
The Async pipe saves boilerplate in the component code.
The component doesn't have to subscribe to the async data source,
2015-10-23 12:31:51 -04:00
it doesn't extract the resolved values and expose them for binding,
2016-01-13 17:00:43 -05:00
and the component doesn't have to unsubscribe when it is destroyed
2015-10-19 12:56:24 -04:00
(a potent source of memory leaks).
2015-11-10 13:31:46 -05:00
2016-01-13 17:00:43 -05:00
### An impure caching pipe
2016-05-13 16:44:14 -04:00
Let's write one more impure pipe, a pipe that makes an HTTP request to the server.
2016-04-06 14:15:07 -04:00
Normally, that's a horrible idea.
2016-01-13 17:00:43 -05:00
It's probably a horrible idea no matter what we do.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
If we're not careful, this pipe will punish the server with requests.
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
We are careful. Our pipe only makes a server call if the request URL has changed.
It caches the request URL and waits for a result which it also caches when it arrives.
The pipe returns the cached result (which is null while a request is in flight)
after every Angular call and only contacts the server as necessary.
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
Here's the code, which uses the [Angular http](server-communication.html) facility
to retrieve a `heroes.json` file:
2015-10-19 12:56:24 -04:00
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
2015-11-10 13:31:46 -05:00
:marked
2016-01-13 17:00:43 -05:00
Then we demonstrate it in a harness component whose template defines two bindings to this pipe.
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)')
:marked
2016-04-06 14:15:07 -04:00
Despite the two bindings and what we know to be frequent pipe calls,
2016-01-13 17:00:43 -05:00
the nework tab in the browser developer tools confirms that there is only one request for the file.
2016-04-06 14:15:07 -04:00
2015-12-13 01:01:46 -05:00
The component renders like this:
2016-05-13 16:44:14 -04:00
2015-11-02 03:28:38 -05:00
figure.image-display
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
2016-05-13 16:44:14 -04:00
2015-12-13 01:01:46 -05:00
:marked
2016-01-13 17:00:43 -05:00
### *JsonPipe*
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
The second binding involving the `FetchPipe` uses more pipe chaining.
2016-04-06 14:15:07 -04:00
We take the same fetched results displayed in the first binding
2016-01-13 17:00:43 -05:00
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
2016-04-06 14:15:07 -04:00
2015-12-13 01:01:46 -05:00
.callout.is-helpful
header Debugging with the json pipe
:marked
2016-03-17 00:42:55 -04:00
The [JsonPipe](../api/common/JsonPipe-class.html)
2016-01-13 17:00:43 -05:00
provides an easy way to diagnosis a mysteriously failing data binding or
2016-04-06 14:15:07 -04:00
inspect an object for future binding.
2016-05-13 16:44:14 -04:00
2015-12-13 01:01:46 -05:00
:marked
Here's the complete component implementation:
2016-05-13 16:44:14 -04:00
2015-12-13 01:01:46 -05:00
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
2016-01-13 17:00:43 -05:00
a(id="pure-pipe-pure-fn")
:marked
2016-04-20 20:12:21 -04:00
### Pure pipes and pure functions
2016-04-06 14:15:07 -04:00
2016-04-20 20:12:21 -04:00
A pure pipe uses pure functions.
2016-04-06 14:15:07 -04:00
Pure functions process inputs and return values without detectable side-effects.
2016-01-13 17:00:43 -05:00
Given the same input they should always return the same output.
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
The pipes we saw earlier in this chapter were implemented with pure functions.
2016-04-06 14:15:07 -04:00
The built-in `DatePipe` is a pure pipe with a pure function implementation.
2016-01-13 17:00:43 -05:00
So is our `ExponentialStrengthPipe`.
So is our `FlyingHeroesPipe`.
A few steps back we reviewed the `FlyingHeroesImpurePipe` — *an impure pipe with a pure function*.
2016-05-27 05:40:44 -04:00
2016-04-20 20:12:21 -04:00
But a *pure pipe* must always be implemented with a *pure function*. Failure to heed this warning will bring about many a console errors regarding expressions that have changed after they were checked.
2015-10-23 12:31:51 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-23 12:31:51 -04:00
## Next Steps
2015-11-10 13:31:46 -05:00
2015-10-23 12:31:51 -04:00
Pipes are a great way to encapsulate and share common display-value
transformations. We use them like styles, dropping them
into our templates expressions to enrich the appeal and usability
of our views.
2015-11-10 13:31:46 -05:00
2016-01-13 17:00:43 -05:00
Explore Angular's inventory of built-in pipes in the [API Reference](../api/#!?apiFilter=pipe).
2015-11-17 13:17:14 -05:00
Try writing a custom pipe and perhaps contributing it to the community.
2016-01-13 17:00:43 -05:00
a(id="no-filter-pipe")
.l-main-section
:marked
## No *FilterPipe* or *OrderByPipe*
2016-05-13 16:44:14 -04:00
2016-01-13 17:00:43 -05:00
Angular does not ship with pipes for filtering or sorting lists.
Developers familiar with Angular 1 know these as `filter` and `orderBy`.
2016-04-06 14:15:07 -04:00
There are no equivalents in Angular 2.
2016-01-13 17:00:43 -05:00
This is not an oversight. Angular 2 is unlikely to offer such pipes because
(a) they perform poorly and (b) they prevent aggressive minification.
2016-05-13 16:44:14 -04:00
Both `filter` and `orderBy` require parameters that reference object properties.
2016-01-13 17:00:43 -05:00
We learned earlier that such pipes must be [*impure*](#pure-and-impure-pipes) and that
Angular calls impure pipes in almost every change detection cycle.
2016-04-06 14:15:07 -04:00
Filtering and especially sorting are expensive operations.
2016-01-13 17:00:43 -05:00
The user experience can degrade severely for even moderate sized lists when Angular calls these pipe methods many times per second.
The `filter` and `orderBy` have often been abused in Angular 1 apps, leading to complaints that Angular itself is slow.
2016-04-06 14:15:07 -04:00
That charge is fair in the indirect sense that Angular 1 prepared this performance trap
2016-01-13 17:00:43 -05:00
by offering `filter` and `orderBy` in the first place.
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
The minification hazard is also compelling if less obvious. Imagine a sorting pipe applied to a list of heroes.
2016-05-13 16:44:14 -04:00
We might sort the list by hero `name` and `planet` of origin properties something like this:
code-example(language="html")
2016-01-13 17:00:43 -05:00
<!-- NOT REAL CODE! -->
2016-05-01 18:29:25 -04:00
<div *ngFor="let hero of heroes | orderBy:'name,planet'"></div>
2016-01-13 17:00:43 -05:00
:marked
We identify the sort fields by text strings, expecting the pipe to reference a property value by indexing
(e.g., `hero['name']`).
Unfortunately, aggressive minification *munges* the `Hero` property names so that `Hero.name` and `Hero.planet`
becomes something like `Hero.a` and `Hero.b`. Clearly `hero['name']` is not going to work.
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
Some of us may not care to minify this aggressively. That's *our* choice.
But the Angular product should not prevent someone else from minifying aggressively.
Therefore, the Angular team decided that everything shipped in Angular will minify safely.
2016-04-06 14:15:07 -04:00
2016-01-13 17:00:43 -05:00
The Angular team and many experienced Angular developers strongly recommend that you move
2016-04-06 14:15:07 -04:00
filtering and sorting logic into the component itself.
2016-01-13 17:00:43 -05:00
The component can expose a `filteredHeroes` or `sortedHeroes` property and take control
2016-04-06 14:15:07 -04:00
over when and how often to execute the supporting logic.
Any capabilities that you would have put in a pipe and shared across the app can be
2016-01-13 17:00:43 -05:00
written in a filtering/sorting service and injected into the component.
2016-04-06 14:15:07 -04:00
If these performance and minification considerations do not apply to you, you can always create your own such pipes
2016-01-13 17:00:43 -05:00
(along the lines of the [FlyingHeroesPipe](#impure-flying-heroes)) or find them in the community.