docs(pipes): Fixed "If follows..." typo
closes #1053 Fixed typo in **pipes** section of guide.
This commit is contained in:
parent
8c7b991e4f
commit
fdb57381e3
@ -16,7 +16,7 @@ include ../_util-fns
|
|||||||
In fact, we'd like to apply them in our HTML templates as we do styles.
|
In fact, we'd like to apply them in our HTML templates as we do styles.
|
||||||
|
|
||||||
Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML!
|
Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML!
|
||||||
|
|
||||||
[Live Example](/resources/live-examples/pipes/ts/plnkr.html).
|
[Live Example](/resources/live-examples/pipes/ts/plnkr.html).
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
@ -29,11 +29,11 @@ include ../_util-fns
|
|||||||
+makeExample('pipes/ts/app/hero-birthday1.component.ts', null, 'app/hero-birthday1.component.ts')(format='.')
|
+makeExample('pipes/ts/app/hero-birthday1.component.ts', null, 'app/hero-birthday1.component.ts')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Focus on the component's template.
|
Focus on the component's template.
|
||||||
+makeExample('pipes/ts/app/app.component.html', 'hero-birthday-template')(format=".")
|
+makeExample('pipes/ts/app/app.component.html', 'hero-birthday-template')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Inside the interpolation expression we flow the component's `birthday` value through the
|
Inside the interpolation expression we flow the component's `birthday` value through the
|
||||||
[pipe operator](./template-syntax.html#pipe) ( | ) to the [Date pipe](../api/common/DatePipe-class.html)
|
[pipe operator](./template-syntax.html#pipe) ( | ) to the [Date pipe](../api/common/DatePipe-class.html)
|
||||||
function on the right. All pipes work this way.
|
function on the right. All pipes work this way.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
@ -46,7 +46,7 @@ include ../_util-fns
|
|||||||
:marked
|
:marked
|
||||||
Learn more about these and many other built-in pipes in the the [API Reference](../api/#!?apiFilter=pipe);
|
Learn more about these and many other built-in pipes in the the [API Reference](../api/#!?apiFilter=pipe);
|
||||||
filter for entries that include the word "pipe".
|
filter for entries that include the word "pipe".
|
||||||
|
|
||||||
Angular 2 doesn't have a `FilterPipe` or an `OrderByPipe` for reasons explained in an [appendix below](#no-filter-pipe)
|
Angular 2 doesn't have a `FilterPipe` or an `OrderByPipe` for reasons explained in an [appendix below](#no-filter-pipe)
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
@ -65,9 +65,9 @@ include ../_util-fns
|
|||||||
:marked
|
:marked
|
||||||
The parameter value can be any valid
|
The parameter value can be any valid
|
||||||
[template expression](./template-syntax.html#template-expressions)
|
[template expression](./template-syntax.html#template-expressions)
|
||||||
such as a string literal or a component property.
|
such as a string literal or a component property.
|
||||||
In other words, we can control the format through a binding the same way we control the birthday value through a binding.
|
In other words, we can control the format through a binding the same way we control the birthday value through a binding.
|
||||||
|
|
||||||
Let's write a second component that *binds* the pipe's format parameter
|
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:
|
to the component's `format` property. Here's the template for that component:
|
||||||
+makeExample('pipes/ts/app/hero-birthday2.component.ts', 'template', 'app/hero-birthday2.component.ts (template)')(format=".")
|
+makeExample('pipes/ts/app/hero-birthday2.component.ts', 'template', 'app/hero-birthday2.component.ts (template)')(format=".")
|
||||||
@ -106,7 +106,7 @@ figure.image-display
|
|||||||
+makeExample('pipes/ts/app/app.component.html', 'chained-parameter-birthday')(format=".")
|
+makeExample('pipes/ts/app/app.component.html', 'chained-parameter-birthday')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We can add parentheses to alter the evaluation order or
|
We can add parentheses to alter the evaluation order or
|
||||||
to provide extra clarity:
|
to provide extra clarity:
|
||||||
+makeExample('pipes/ts/app/app.component.html', 'chained-parameter-birthday-parens')(format=".")
|
+makeExample('pipes/ts/app/app.component.html', 'chained-parameter-birthday-parens')(format=".")
|
||||||
|
|
||||||
@ -121,17 +121,17 @@ figure.image-display
|
|||||||
+makeExample('pipes/ts/app/exponential-strength.pipe.ts', null, 'app/exponential-strength.pipe.ts')(format=".")
|
+makeExample('pipes/ts/app/exponential-strength.pipe.ts', null, 'app/exponential-strength.pipe.ts')(format=".")
|
||||||
:marked
|
:marked
|
||||||
This pipe definition reveals several key points
|
This pipe definition reveals several key points
|
||||||
|
|
||||||
* A pipe is a class decorated with pipe metadata.
|
* A pipe is a class decorated with pipe metadata.
|
||||||
|
|
||||||
* The pipe class implements the `PipeTransform` interface's `transform` method that
|
* The pipe class implements the `PipeTransform` interface's `transform` method that
|
||||||
accepts an input value and an optional array of parameters and returns the transformed value.
|
accepts an input value and an optional array of parameters and returns the transformed value.
|
||||||
|
|
||||||
* There will be one item in the parameter array for each parameter passed to the pipe
|
* There will be one item in the parameter array for each parameter passed to the pipe
|
||||||
|
|
||||||
* We tell Angular that this is a pipe by applying the
|
* We tell Angular that this is a pipe by applying the
|
||||||
`@Pipe` decorator which we import from the core Angular library.
|
`@Pipe` decorator which we import from the core Angular library.
|
||||||
|
|
||||||
* The `@Pipe` decorator takes an object with a name property whose value is the
|
* The `@Pipe` decorator takes an object with a name property whose value is the
|
||||||
pipe name that we'll use within a template expression. It must be a valid JavaScript identifier.
|
pipe name that we'll use within a template expression. It must be a valid JavaScript identifier.
|
||||||
Our pipe's name is `exponentialStrength`.
|
Our pipe's name is `exponentialStrength`.
|
||||||
@ -140,10 +140,10 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
### The *PipeTransform* Interface
|
### The *PipeTransform* Interface
|
||||||
|
|
||||||
The `transform` method is essential to a pipe.
|
The `transform` method is essential to a pipe.
|
||||||
The `PipeTransform` *interface* defines that method and guides both tooling and the compiler.
|
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.
|
It is technically optional; Angular looks for and executes the `transform` method regardless.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Now we need a component to demonstrate our pipe.
|
Now we need a component to demonstrate our pipe.
|
||||||
+makeExample('pipes/ts/app/power-booster.component.ts',null,'app/power-booster.component.ts')(format='.')
|
+makeExample('pipes/ts/app/power-booster.component.ts',null,'app/power-booster.component.ts')(format='.')
|
||||||
@ -182,12 +182,12 @@ a(id="change-detection")
|
|||||||
:marked
|
:marked
|
||||||
## Pipes and Change Detection
|
## Pipes and Change Detection
|
||||||
Angular looks for changes to data-bound values through a *change detection* process that runs after every JavaScript event:
|
Angular looks for changes to data-bound values through a *change detection* process that runs after every JavaScript event:
|
||||||
every keystroke, mouse move, timer tick, and server response. It could be expensive.
|
every keystroke, mouse move, timer tick, and server response. It could be expensive.
|
||||||
Angular strives to lower the cost whenever possible and appropriate.
|
Angular strives to lower the cost whenever possible and appropriate.
|
||||||
|
|
||||||
Angular picks a simpler, faster change detection algorithm when we use a pipe. Let's see how.
|
Angular picks a simpler, faster change detection algorithm when we use a pipe. Let's see how.
|
||||||
|
|
||||||
### No pipe
|
### No pipe
|
||||||
The component in our next example uses the default, aggressive change detection strategy to monitor and update
|
The component in our next example uses the default, aggressive change detection strategy to monitor and update
|
||||||
its display of every hero in the `heroes` array. Here's the template:
|
its display of every hero in the `heroes` array. Here's the template:
|
||||||
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-1', 'app/flying-heroes.component.html (v1)')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-1', 'app/flying-heroes.component.html (v1)')(format='.')
|
||||||
@ -195,12 +195,12 @@ a(id="change-detection")
|
|||||||
The companion component class provides heroes, pushes new heroes into the array, and can reset the array.
|
The companion component class provides heroes, pushes new heroes into the array, and can reset the array.
|
||||||
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'v1', 'app/flying-heroes.component.ts (v1)')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'v1', 'app/flying-heroes.component.ts (v1)')(format='.')
|
||||||
:marked
|
:marked
|
||||||
We can add a new hero and Angular updates the display when we do.
|
We can add a new hero and Angular updates the display when we do.
|
||||||
The `reset` button replaces `heroes` with a new array of the original heroes and Angular updates the display when we do.
|
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 again.
|
If we added the ability to remove or change a hero, Angular would detect those changes too and update the display again.
|
||||||
add or remove heroes. It updates the display when we modify a hero.
|
add or remove heroes. It updates the display when we modify a hero.
|
||||||
|
|
||||||
### Flying Heroes pipe
|
### Flying Heroes pipe
|
||||||
Let's add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
|
Let's add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
|
||||||
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-flying-heroes', 'app/flying-heroes.component.html (flyers)')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.component.html', 'template-flying-heroes', 'app/flying-heroes.component.html (flyers)')(format='.')
|
||||||
:marked
|
:marked
|
||||||
@ -209,23 +209,23 @@ a(id="change-detection")
|
|||||||
|
|
||||||
:marked
|
:marked
|
||||||
When we run the sample now we see odd behavior (try it in the [live example](/resources/live-examples/pipes/ts/plnkr.html)).
|
When we run the sample now we see odd behavior (try it in the [live example](/resources/live-examples/pipes/ts/plnkr.html)).
|
||||||
Every hero we add is a flying hero but none of them are displayed.
|
Every hero we add is a flying hero but none of them are displayed.
|
||||||
|
|
||||||
Although we're not getting the behavior we want, Angular isn't broken.
|
Although we're not getting the behavior we want, Angular isn't broken.
|
||||||
It's just using a different change detection algorithm — one that ignores changes to the list or any of its items.
|
It's just using a different change detection algorithm — one that ignores changes to the list or any of its items.
|
||||||
|
|
||||||
Look at how we're adding a new hero:
|
Look at how we're adding a new hero:
|
||||||
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'push')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.component.ts', 'push')(format='.')
|
||||||
:marked
|
:marked
|
||||||
We're pushing the new hero into the `heroes` array. The object reference to the array hasn't changed.
|
We're pushing the new hero into the `heroes` array. The object 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*.
|
It's the same array. That's all Angular cares about. From its perspective, *same array, no change, no display update*.
|
||||||
|
|
||||||
We can fix that. Let's use `concat` to create a new array with the new hero appended and assign that to `heroes`.
|
We can fix that. Let's use `concat` to create a new array with the new hero appended and assign that to `heroes`.
|
||||||
This time Angular detects that the array object reference has changed.
|
This time Angular detects that the array object reference has changed.
|
||||||
It executes the pipe and updates the display with the new array which includes the new flying hero.
|
It executes the pipe and updates the display with the new array which includes the new flying hero.
|
||||||
|
|
||||||
*If we **mutate** the array, no pipe and no display update;
|
*If we **mutate** the array, no pipe and no display update;
|
||||||
if we **replace** the array, the pipe executes and the display updates*.
|
if we **replace** the array, the pipe executes and the display updates*.
|
||||||
|
|
||||||
The *Flying Heroes* in the [live example](/resources/live-examples/pipes/ts/plnkr.html) extends the
|
The *Flying Heroes* in the [live example](/resources/live-examples/pipes/ts/plnkr.html) extends the
|
||||||
code with checkbox switches and additional displays to help us experience these effects.
|
code with checkbox switches and additional displays to help us experience these effects.
|
||||||
@ -235,97 +235,97 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
Replacing the array is an efficient way to signal to Angular that it should update the display.
|
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.
|
When do we replace the array? When the data change.
|
||||||
|
|
||||||
That's an easy rule to follow in *this toy* example
|
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.
|
where the only way to change the data is by adding a new hero.
|
||||||
|
|
||||||
More often we don't know when the data have changed,
|
More often we don't know when the data have changed,
|
||||||
especially in applications that mutate data in many ways,
|
especially in applications that mutate data in many ways,
|
||||||
perhaps in application locations far away.
|
perhaps in application locations far away.
|
||||||
A component is such an application usually can't know about those changes.
|
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.
|
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.
|
We strive as much as possible to keep the component class independent of the HTML.
|
||||||
The component should be unaware of pipes.
|
The component should be unaware of pipes.
|
||||||
|
|
||||||
Perhaps we should consider a different kind of pipe for filtering flying heroes, an *impure pipe*.
|
Perhaps we should consider a different kind of pipe for filtering flying heroes, an *impure pipe*.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Pure and Impure Pipes
|
## Pure and Impure Pipes
|
||||||
|
|
||||||
There are two categories of pipes: **pure** and **impure**.
|
There are two categories of pipes: **pure** and **impure**.
|
||||||
|
|
||||||
Pipes are pure by default. Every pipe we've seen so far has been pure.
|
Pipes are pure by default. Every pipe we've seen so far has been pure.
|
||||||
|
|
||||||
We make a pipe impure by setting its pure flag to false. We could make the `FlyingHeroesPipe`
|
We make a pipe impure by setting its pure flag to false. We could make the `FlyingHeroesPipe`
|
||||||
impure with a flip of the switch:
|
impure with a flip of the switch:
|
||||||
|
|
||||||
+makeExample('pipes/ts/app/flying-heroes.pipe.ts', 'pipe-decorator')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.pipe.ts', 'pipe-decorator')(format='.')
|
||||||
:marked
|
:marked
|
||||||
Before we do that, let's understand the difference between *pure* and *impure*, starting with a *pure* pipe.
|
Before we do that, let's understand the difference between *pure* and *impure*, starting with a *pure* pipe.
|
||||||
|
|
||||||
### Pure pipes
|
### Pure pipes
|
||||||
|
|
||||||
Angular executes a *pure pipe* only when it detects a *pure change* to the input value.
|
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`)
|
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`).
|
*or* a changed object reference (`Date`, `Array`, `Function`, `Object`).
|
||||||
|
|
||||||
Angular ignores changes *within* the object itself.
|
Angular ignores changes *within* the object itself.
|
||||||
It won't call a pure pipe if we change the input month, add to the input array, or update an input object property.
|
It won't call a pure pipe if we change the input month, add to the input array, or update an input object property.
|
||||||
|
|
||||||
This may seem restrictive but is is also fast.
|
This may seem restrictive but is is also fast.
|
||||||
An object reference check is fast ... much faster than a deep check for differences.
|
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 screen update.
|
... so Angular can quickly determine if it can skip both the pipe execution and a screen update.
|
||||||
|
|
||||||
For this reason, we prefer a pure pipe if we can live with the change detection strategy.
|
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.
|
When we can't, we *may* turn to the impure pipe.
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Or we might not use a pipe at all.
|
Or we might not use a pipe at all.
|
||||||
It may be better to pursue the pipe's purpose with a property of the component,
|
It may be better to pursue the pipe's purpose with a property of the component,
|
||||||
a point we take up later.
|
a point we take up later.
|
||||||
:marked
|
:marked
|
||||||
### Impure pipes
|
### Impure pipes
|
||||||
Angular executes an *impure pipe* during *every* component change detection cycle.
|
Angular executes an *impure pipe* during *every* component change detection cycle.
|
||||||
An impure pipe will be called a lot, as often as every keystroke or mouse-move.
|
An impure pipe will be called a lot, as often as every keystroke or mouse-move.
|
||||||
|
|
||||||
If follows that we must implement an impure pipe with great care.
|
With that concern in mind, we must implement an impure pipe with great care.
|
||||||
An expensive, long-running pipe could destroy the user experience.
|
An expensive, long-running pipe could destroy the user experience.
|
||||||
|
|
||||||
<a id="impure-flying-heroes"></a>
|
<a id="impure-flying-heroes"></a>
|
||||||
### An impure *FlyingHeroesPipe*
|
### An impure *FlyingHeroesPipe*
|
||||||
|
|
||||||
A flip of the switch turns our `FlyingHeroesPipe` into a `FlyingHeroesImpurePipe`.
|
A flip of the switch turns our `FlyingHeroesPipe` into a `FlyingHeroesImpurePipe`.
|
||||||
Here's the complete implementation:
|
Here's the complete implementation:
|
||||||
+makeTabs(
|
+makeTabs(
|
||||||
'pipes/ts/app/flying-heroes.pipe.ts, pipes/ts/app/flying-heroes.pipe.ts',
|
'pipes/ts/app/flying-heroes.pipe.ts, pipes/ts/app/flying-heroes.pipe.ts',
|
||||||
'impure, pure',
|
'impure, pure',
|
||||||
'FlyingHeroesImpurePipe, FlyingHeroesPipe')(format='.')
|
'FlyingHeroesImpurePipe, FlyingHeroesPipe')(format='.')
|
||||||
:marked
|
:marked
|
||||||
We inherit from `FlyingHeroesPipe` to prove the point that nothing changed internally.
|
We inherit from `FlyingHeroesPipe` to prove the point that nothing changed internally.
|
||||||
The only difference is the `pure` flag in the pipe metadata.
|
The only difference is the `pure` flag in the pipe metadata.
|
||||||
|
|
||||||
This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
|
This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
|
||||||
+makeExample('pipes/ts/app/flying-heroes.pipe.ts','filter')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.pipe.ts','filter')(format='.')
|
||||||
|
|
||||||
We can derive a `FlyingHeroesImpureComponent` that we derive from the `FlyingHeroesComponent`.
|
We can derive a `FlyingHeroesImpureComponent` that we derive from the `FlyingHeroesComponent`.
|
||||||
+makeExample('pipes/ts/app/flying-heroes.component.ts','impure-component','app/flying-heroes.component.ts (FlyingHeroesImpureComponent)')(format='.')
|
+makeExample('pipes/ts/app/flying-heroes.component.ts','impure-component','app/flying-heroes.component.ts (FlyingHeroesImpureComponent)')(format='.')
|
||||||
:marked
|
:marked
|
||||||
The only substantive change is the pipe.
|
The only substantive change is the pipe.
|
||||||
We can confirm in the [live example](/resources/live-examples/pipes/ts/plnkr.html)
|
We can confirm in the [live example](/resources/live-examples/pipes/ts/plnkr.html)
|
||||||
that the *flying heroes* display updates as we enter new heroes even when we mutate the `heroes` array.
|
that the *flying heroes* display updates as we enter new heroes even when we mutate the `heroes` array.
|
||||||
|
|
||||||
<a id="async-pipe"></a>
|
<a id="async-pipe"></a>
|
||||||
### The impure *AsyncPipe*
|
### The impure *AsyncPipe*
|
||||||
The Angular `AsyncPipe` is an interesting example of an impure pipe.
|
The Angular `AsyncPipe` is an interesting example of an impure pipe.
|
||||||
The `AsyncPipe` accepts a `Promise` or `Observable` as input
|
The `AsyncPipe` accepts a `Promise` or `Observable` as input
|
||||||
and subscribes to the input automatically, eventually returning the emitted value(s).
|
and subscribes to the input automatically, eventually returning the emitted value(s).
|
||||||
|
|
||||||
It is also stateful.
|
It is also stateful.
|
||||||
The pipe maintains a subscription to the input `Observable` and
|
The pipe maintains a subscription to the input `Observable` and
|
||||||
keeps delivering values from that `Observable` as they arrive.
|
keeps delivering values from that `Observable` as they arrive.
|
||||||
|
|
||||||
In this next example, we bind an `Observable` of message strings (`messages$`) to a view with the `async` pipe.
|
In this next example, we bind an `Observable` of message strings (`messages$`) to a view with the `async` pipe.
|
||||||
@ -341,19 +341,19 @@ figure.image-display
|
|||||||
### An impure caching pipe
|
### An impure caching pipe
|
||||||
|
|
||||||
Let's write one more impure pipe, a pipe that makes an http request to the server.
|
Let's write one more impure pipe, a pipe that makes an http request to the server.
|
||||||
|
|
||||||
Normally, that's a horrible idea.
|
Normally, that's a horrible idea.
|
||||||
It's probably a horrible idea no matter what we do.
|
It's probably a horrible idea no matter what we do.
|
||||||
We're forging ahead anyway to make a point.
|
We're forging ahead anyway to make a point.
|
||||||
|
|
||||||
Remember that impure pipes are called every few microseconds.
|
Remember that impure pipes are called every few microseconds.
|
||||||
If we're not careful, this pipe will punish the server with requests.
|
If we're not careful, this pipe will punish the server with requests.
|
||||||
|
|
||||||
We are careful. Our pipe only makes a server call if the request URL has changed.
|
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.
|
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)
|
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.
|
after every Angular call and only contacts the server as necessary.
|
||||||
|
|
||||||
Here's the code, which uses the [Angular http](server-communication.html) facility
|
Here's the code, which uses the [Angular http](server-communication.html) facility
|
||||||
to retrieve a `heroes.json` file:
|
to retrieve a `heroes.json` file:
|
||||||
|
|
||||||
@ -362,24 +362,24 @@ figure.image-display
|
|||||||
Then we demonstrate it in a harness component whose template defines two bindings to this pipe.
|
Then we demonstrate it in a harness component whose template defines two bindings to this pipe.
|
||||||
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)')
|
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)')
|
||||||
:marked
|
:marked
|
||||||
Despite the two bindings and what we know to be frequent pipe calls,
|
Despite the two bindings and what we know to be frequent pipe calls,
|
||||||
the nework tab in the browser developer tools confirms that there is only one request for the file.
|
the nework tab in the browser developer tools confirms that there is only one request for the file.
|
||||||
|
|
||||||
The component renders like this:
|
The component renders like this:
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
|
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
|
||||||
:marked
|
:marked
|
||||||
### *JsonPipe*
|
### *JsonPipe*
|
||||||
The second binding involving the `FetchPipe` uses more pipe chaining.
|
The second binding involving the `FetchPipe` uses more pipe chaining.
|
||||||
We take the same fetched results displayed in the first binding
|
We take the same fetched results displayed in the first binding
|
||||||
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
|
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
|
||||||
|
|
||||||
.callout.is-helpful
|
.callout.is-helpful
|
||||||
header Debugging with the json pipe
|
header Debugging with the json pipe
|
||||||
:marked
|
:marked
|
||||||
The [JsonPipe](../api/common/JsonPipe-class.html)
|
The [JsonPipe](../api/common/JsonPipe-class.html)
|
||||||
provides an easy way to diagnosis a mysteriously failing data binding or
|
provides an easy way to diagnosis a mysteriously failing data binding or
|
||||||
inspect an object for future binding.
|
inspect an object for future binding.
|
||||||
:marked
|
:marked
|
||||||
Here's the complete component implementation:
|
Here's the complete component implementation:
|
||||||
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
|
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
|
||||||
@ -387,21 +387,21 @@ figure.image-display
|
|||||||
a(id="pure-pipe-pure-fn")
|
a(id="pure-pipe-pure-fn")
|
||||||
:marked
|
:marked
|
||||||
### Pure pipes vs. pure functions
|
### Pure pipes vs. pure functions
|
||||||
|
|
||||||
When developers first hear of *pure pipes* many of them think these pipes must be *pure functions*.
|
When developers first hear of *pure pipes* many of them think these pipes must be *pure functions*.
|
||||||
|
|
||||||
Pure functions process inputs and return values without detectable side-effects.
|
Pure functions process inputs and return values without detectable side-effects.
|
||||||
Given the same input they should always return the same output.
|
Given the same input they should always return the same output.
|
||||||
|
|
||||||
Pure pipes _are_ typically implemented with pure function.
|
Pure pipes _are_ typically implemented with pure function.
|
||||||
The pipes we saw earlier in this chapter were implemented with pure functions.
|
The pipes we saw earlier in this chapter were implemented with pure functions.
|
||||||
The built-in `DatePipe` is a pure pipe with a pure function implementation.
|
The built-in `DatePipe` is a pure pipe with a pure function implementation.
|
||||||
So is our `ExponentialStrengthPipe`.
|
So is our `ExponentialStrengthPipe`.
|
||||||
So is our `FlyingHeroesPipe`.
|
So is our `FlyingHeroesPipe`.
|
||||||
|
|
||||||
But there is no necessary connection between a pure pipe and a pure function.
|
But there is no necessary connection between a pure pipe and a pure function.
|
||||||
A few steps back we reviewed the `FlyingHeroesImpurePipe` — *an impure pipe with a pure function*.
|
A few steps back we reviewed the `FlyingHeroesImpurePipe` — *an impure pipe with a pure function*.
|
||||||
|
|
||||||
We can also write *a pure pipe with an impure function* such as the
|
We can also write *a pure pipe with an impure function* such as the
|
||||||
`RandomizerPipe` (also in the [live example](/resources/live-examples/pipes/ts/plnkr.html))
|
`RandomizerPipe` (also in the [live example](/resources/live-examples/pipes/ts/plnkr.html))
|
||||||
that ignores its input value and outputs a random number. Clearly an impure function!
|
that ignores its input value and outputs a random number. Clearly an impure function!
|
||||||
@ -409,9 +409,9 @@ a(id="pure-pipe-pure-fn")
|
|||||||
+makeExample('pipes/ts/app/random-pipe.component.ts', 'pipe','app/random-pipe.component.ts (pipe)')(format='.')
|
+makeExample('pipes/ts/app/random-pipe.component.ts', 'pipe','app/random-pipe.component.ts (pipe)')(format='.')
|
||||||
:marked
|
:marked
|
||||||
When the input changes, it outputs a new value albeit never the same value for the same input.
|
When the input changes, it outputs a new value albeit never the same value for the same input.
|
||||||
|
|
||||||
Remember *purity in a pipe has nothing to do with pure functions!*
|
Remember *purity in a pipe has nothing to do with pure functions!*
|
||||||
|
|
||||||
*Pipe purity* is more about the purity of the input values than of the pipe itself.
|
*Pipe purity* is more about the purity of the input values than of the pipe itself.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
@ -432,21 +432,21 @@ a(id="no-filter-pipe")
|
|||||||
## No *FilterPipe* or *OrderByPipe*
|
## No *FilterPipe* or *OrderByPipe*
|
||||||
Angular does not ship with pipes for filtering or sorting lists.
|
Angular does not ship with pipes for filtering or sorting lists.
|
||||||
Developers familiar with Angular 1 know these as `filter` and `orderBy`.
|
Developers familiar with Angular 1 know these as `filter` and `orderBy`.
|
||||||
There are no equivalents in Angular 2.
|
There are no equivalents in Angular 2.
|
||||||
|
|
||||||
This is not an oversight. Angular 2 is unlikely to offer such pipes because
|
This is not an oversight. Angular 2 is unlikely to offer such pipes because
|
||||||
(a) they perform poorly and (b) they prevent aggressive minification.
|
(a) they perform poorly and (b) they prevent aggressive minification.
|
||||||
|
|
||||||
Both *filter* and *orderBy* require parameters that reference object properties.
|
Both *filter* and *orderBy* require parameters that reference object properties.
|
||||||
We learned earlier that such pipes must be [*impure*](#pure-and-impure-pipes) and that
|
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.
|
Angular calls impure pipes in almost every change detection cycle.
|
||||||
|
|
||||||
Filtering and especially sorting are expensive operations.
|
Filtering and especially sorting are expensive operations.
|
||||||
The user experience can degrade severely for even moderate sized lists when Angular calls these pipe methods many times per second.
|
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.
|
The `filter` and `orderBy` have often been abused in Angular 1 apps, leading to complaints that Angular itself is slow.
|
||||||
That charge is fair in the indirect sense that Angular 1 prepared this performance trap
|
That charge is fair in the indirect sense that Angular 1 prepared this performance trap
|
||||||
by offering `filter` and `orderBy` in the first place.
|
by offering `filter` and `orderBy` in the first place.
|
||||||
|
|
||||||
The minification hazard is also compelling if less obvious. Imagine a sorting pipe applied to a list of heroes.
|
The minification hazard is also compelling if less obvious. Imagine a sorting pipe applied to a list of heroes.
|
||||||
We might sort the list by hero `name` and `planet` origin properties something like this:
|
We might sort the list by hero `name` and `planet` origin properties something like this:
|
||||||
code-example(format="." language="html")
|
code-example(format="." language="html")
|
||||||
@ -457,18 +457,18 @@ code-example(format="." language="html")
|
|||||||
(e.g., `hero['name']`).
|
(e.g., `hero['name']`).
|
||||||
Unfortunately, aggressive minification *munges* the `Hero` property names so that `Hero.name` and `Hero.planet`
|
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.
|
becomes something like `Hero.a` and `Hero.b`. Clearly `hero['name']` is not going to work.
|
||||||
|
|
||||||
Some of us may not care to minify this aggressively. That's *our* choice.
|
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.
|
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.
|
Therefore, the Angular team decided that everything shipped in Angular will minify safely.
|
||||||
|
|
||||||
The Angular team and many experienced Angular developers strongly recommend that you move
|
The Angular team and many experienced Angular developers strongly recommend that you move
|
||||||
filtering and sorting logic into the component itself.
|
filtering and sorting logic into the component itself.
|
||||||
The component can expose a `filteredHeroes` or `sortedHeroes` property and take control
|
The component can expose a `filteredHeroes` or `sortedHeroes` property and take control
|
||||||
over when and how often to execute the supporting logic.
|
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
|
Any capabilities that you would have put in a pipe and shared across the app can be
|
||||||
written in a filtering/sorting service and injected into the component.
|
written in a filtering/sorting service and injected into the component.
|
||||||
|
|
||||||
If these performance and minification considerations do not apply to you, you can always create your own such pipes
|
If these performance and minification considerations do not apply to you, you can always create your own such pipes
|
||||||
(along the lines of the [FlyingHeroesPipe](#impure-flying-heroes)) or find them in the community.
|
(along the lines of the [FlyingHeroesPipe](#impure-flying-heroes)) or find them in the community.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user