7.8 KiB
title |
---|
Pipes |
Pipes
Motivation
Output data transformations. They ensure data is in a desirable format by the time it loads onto the user’s screen. Normally data transforms behind the scenes. With pipes, transforming data can take place in the template HTML. Pipes transform template data directly.
Pipes look nice and are convenient. They help keep the component’s class lean of basic transformations. To put it technically, pipes encapsulate data transformation logic.
Output Transformation
As mentioned in the prior section, pipes transform data inline. The syntax of pipes correlate shell scripting. In many scripts, the output of one part of the command gets piped as output into the next part as input. That same trend characterizes Angular pipes.
In Angular, there exists many ways to interact with data in the template HTML. Pipes can apply anywhere data gets parsed into the template HTML. They can occur within microsyntax logic and innerHTML variable interpolations. Pipes account for all transformations without adding onto the component class.
Pipes are also chainable. You can integrate pipes one after the other to perform increasingly complex transformations. As specialized data transformers, pipes are hardly trivial.
Use Cases
Angular comes prepackaged with a basic set of pipes. Working with a couple of them will develop the intuition to handle the rest. The following list provides two examples.
-
AsyncPipe
-
DatePipe
These two perform simple tasks. Their simplicity is massively beneficial.
AsyncPipe
This sections requires a basic understanding of Promises or Observables to fully appreciate. The AsyncPipe operates on either of the two. AsyncPipe extracts data from Promises/Observables as output for whatever comes next.
In the case of Obervables, AsyncPipe subscribes automatically to the data source. Regardless of where the data comes from, the AsyncPipe subscribes to the source observable. async
is the syntactical name of AsyncPipe as shown below.
<ul *ngFor=“let potato of (potatoSack$ | async); let i=index”>
<li>Potatoe {{i + 1}}: {{potato}}</li>
</ul>
In the example, potatoSack$
is an Observable pending an upload of potatoes. Once the potatoes arrive, either synchronously or asynchronously, the AsyncPipe receives them as an iterable array. The list element then fills up with potatoes.
DatePipe
Formatting date strings takes a fair bit of hacking with the JavaScript Date
object. The DatePipe provides a powerful way to format dates assuming the given input is a valid time format.
// example.component.ts
@Component({
templateUrl: './example.component.html'
})
export class ExampleComponent {
timestamp:string = ‘2018-05-24T19:38:11.103Z’;
}
<!-- example.component.html -->
<div>Current Time: {{timestamp | date:‘short’}}</div>
The format of the above timestamp
is ISO 86011—not the easiest to read. The DatePipe (date
) transforms the ISO date format into a more conventional mm/dd/yy, hh:mm AM|PM
. There are many other formatting options. All these options are in the official documentation.
Creating Pipes
While Angular only has a set number of pipes, the @Pipe
decorator lets developers create their own. The process begins with ng generate pipe [name-of-pipe]
, replacing [name-of-pipe]
with a preferable filename. This is an Angular CLI command. It yields the following.
import { Pipe, PipeTransform } from ‘@angular/core’;
@Pipe({
name: 'example'
})
export class ExamplePipe implements PipeTransform {
transform(value: any, args?: any): any {
return null;
}
}
This pipe template simplifies custom pipe creation. The @Pipe
decorator tells Angular the class is a pipe. The value of name: ‘example’
, in this case being example
, is the value Angular recognizes when scanning template HTML for custom pipes.
On to the class logic. The PipeTransform
implementation provides the instructions for the transform
function. This function has special meaning within context of the @Pipe
decorator. It receives two parameters by default.
value: any
is the output that the pipe receives. Think of <div>{{ someValue | example }}</div>
. The value of someValue gets passed to the transform
function’s value: any
parameter. This is the same transform
function defined in the ExamplePipe class.
args?: any
is any argument that the pipe optionally receives. Think of <div>{{ someValue | example:[some-argument] }}</div>
. [some-argument]
can be replace by any one value. This value gets passed to the transform
function’s args?: any
parameter. That is, the transform
function defined in ExamplePipe's class.
Whatever the function returns (return null;
) becomes the output of the pipe operation. Take a look at the next example to see a complete example of ExamplePipe. Depending on the variable the pipe receives, it either uppercases or lowercases the input as new output. An invalid or nonexistent argument will cause the pipe to return the same input as output.
// example.pipe.ts
@Pipe({
name: 'example'
})
export class ExamplePipe implements PipeTransform {
transform(value:string, args?:string): any {
switch(args || null) {
case 'uppercase':
return value.toUpperCase();
case 'lowercase':
return value.toLowerCase();
default:
return value;
}
}
}
// app.component.ts
@Component({
templateUrl: 'app.component.html'
})
export class AppComponent {
someValue:string = "HeLlO WoRlD!";
}
<!-- app.component.html -->
<!-- Outputs “HeLlO WoRlD!” -->
<h6>{{ someValue | example }}</h6>
<!-- Outputs “HELLO WORLD!” -->
<h6>{{ someValue | example:‘uppercase’ }}</h6>
<!-- Outputs “hello world!” -->
<h6>{{ someValue | example:‘lowercase’ }}</h6>
Understanding the above example means you understand Angular pipes. There is only one more topic left to discuss.
Pure and Impure Pipes
Everything you have seen so far has been a pure pipe. pure: true
is set by default in the @Pipe
decorator's metadata. The difference between the two constitutes Angular’s change detection.
Pure pipes update automatically whenever the value of its derived input changes. The pipe will re-execute to produce new output upon a detectable change in the input value. Detectable changes are determined by Angular’s change detection loop.
Impure pipes update automatically whenever a change detection cycle occurs. Angular’s change detection happens quite often. It signals if changes have occurred in the component class’ member data. If so, the template HTML updates with the updated data. Otherwise, nothing will happen.
In the case of an impure pipe, it will update regardless of whether there is a detectable change or not. An impure pipe updates whenever change detection loops. Impure pipes usually consume lots of resources and are generally ill-advised. That said, they operate more as an escape hatch. If you ever need a detection-sensitive pipe, toggle pure: false
in the @Pipe
decorator’s metadata.
Conclusion
That covers pipes. Pipes have plenty of potential beyond the scope of this article. Pipes contribute succinct data transformations to your components’ template HTML. They are good practice in situations where data must undergo small transformations.