Pipes transform data displayed in templates. They take an input value and optionally arguments, apply formatting or transformation logic, and return the output for display. Angular provides many built-in pipes, and you can create custom pipes for domain-specific needs.
Syntax: {{ expression | pipeName:arg1:arg2 }}
Formats date values according to locale rules:
<p>{{ today | date }}</p>
<p>{{ today | date:'medium' }}</p>
<p>{{ today | date:'yyyy-MM-dd' }}</p>
<p>{{ today | date:'fullDate' }}</p>
Transform text to upper or lower case:
<p>{{ 'hello world' | uppercase }}</p>
<p>{{ 'HELLO WORLD' | lowercase }}</p>
Formats a number as currency with locale-aware symbol placement:
<p>{{ 99.99 | currency }}</p>
<p>{{ 99.99 | currency:'EUR' }}</p>
<p>{{ 99.99 | currency:'INR':'symbol':'4.2-2' }}</p>
Formats a number as a percentage:
<p>{{ 0.25 | percent }}</p>
<p>{{ 0.1234 | percent:'2.1-2' }}</p>
Converts an object to its JSON representation for debugging:
<pre>{{ user | json }}</pre>
Unwraps Observables and Promises directly in templates, automatically subscribing and unsubscribing:
<p>{{ observableData$ | async }}</p>
<ul>
<li *ngFor="let item of items$ | async">{{ item.name }}</li>
</ul>
Formats numbers with decimal places and grouping separators:
<p>{{ 3.14159 | number:'1.2-2' }}</p>
<p>{{ 1234567.89 | number:'5.2-2' }}</p>
Pipes can be chained to apply multiple transformations. Each pipe operates on the output of the previous pipe:
<p>{{ birthday | date:'fullDate' | uppercase }}</p>
<p>{{ price | currency:'USD' | lowercase }}</p>
Order matters — the leftmost pipe is applied first, and its result is passed to the next pipe.
Create a custom pipe using the @Pipe decorator and implementing the PipeTransform interface:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate'
})
export class TruncatePipe implements PipeTransform {
transform(value: string, maxLength: number = 50, suffix: string = '...'): string {
if (!value) return '';
return value.length > maxLength
? value.substring(0, maxLength) + suffix
: value;
}
}
Usage: {{ longText | truncate:30:'…' }}
Pipes are pure by default. A pure pipe only re-evaluates when its input value changes by reference (not mutation). An impure pipe re-evaluates on every change detection cycle, which is useful for pipes that track internal state or handle mutable data.
@Pipe({
name: 'filterArray',
pure: false // Impure pipe - re-evaluates on every change detection
})
export class FilterArrayPipe implements PipeTransform {
transform(items: any[], searchTerm: string): any[] {
if (!items || !searchTerm) return items;
return items.filter(item =>
item.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}
}
You now know how to use built-in Angular pipes (date, uppercase, lowercase, currency, percent, json, async, decimal), chain pipes together, and create custom pipes with the PipeTransform interface. You also understand the distinction between pure and impure pipes and when to use each.
phoneFormat that transforms a 10-digit string into a formatted phone number: (123) 456-7890. Then create a searchFilter pipe (impure) that filters a list of products by name. Use both pipes in a component that displays a searchable, formatted phonebook.