Angular: Custom Pipes
In Angular pipes are used to transform data for example transform some text to uppercase:
<span>{{ message | uppercase }}</span>
The uppercase pipe is a handy built-in pipe. However, it is possible to do much more than transform text. Pipes are a very powerful tool as they allow you to extract code that would otherwise pollute your component into a separate class which is also reusable.
Filter a list with pipes
Here is the definition of a custom pipe that filters a list of strings depending on whether the string contains a provided searchString.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'filterStrings' })
export class FilterStringsPipe implements PipeTransform {
transform(strings: string[], searchString: string = ''): string[] {
if (!searchString) {
return strings;
}
return strings.filter(s => s.indexOf(searchString) != -1);
}
}
To use the pipe simply pipe a list of strings into it as below. To pass an argument to a pipe put a : between the pipe and the argument:
<input [(ngModel)]="searchString" placeholder="Filter"/>
<div *ngFor="let s of strings | filterStrings:searchString">
{{ s }}
</div>
This works with observables as well just add the async pipe:
<!-- if using an observable e.g. Obversable<string[]> -->
<div *ngFor="let s of strings$ | async | filterStrings:searchString">
{{ s }}
</div>
Format distance based on user preferences provided by an injected service
Pipes can have services injected into them. Here the user service is injected into the pipe and used to format the distance using the user’s preferred units i.e. km or miles.
import { Pipe, PipeTransform } from '@angular/core';
import { DistanceUnits, UserService } from '../service/user.service';
@Pipe({ name: 'formatDistance' })
export class FormatDistancePipe implements PipeTransform {
constructor(private userService: UserService) { }
transform(distanceInKm: number): string {
let preferredUnits = this.userService.getDistanceUnits();
let distanceInPreferredUnits = distanceInKm * (preferredUnits == DistanceUnits.MILES ? 0.625 : 1);
return distanceInPreferredUnits.toFixed(1) + preferredUnits;
}
}
Again the usage is simple:
<span>{{ distanceTravel | formatDistance }}</span>
The real benefit here is that the component using the formatDistance pipe doesn’t need to know anything about the user service thus simplifying the component code.