Pipes
|
This section documents modern, standalone Angular — signals, the built-in This content was generated with the assistance of AI and should be verified against angular.dev before being relied on in production. Angular ships a major release roughly every six months and its APIs continue to evolve: the examples here target the current major release; where a consulted source disagrees with the current documentation, the documentation wins and the difference is noted. This section’s bibliography lists the reference material consulted while preparing these pages. |
A pipe transforms a value for display in a template, using the value | pipeName:arg1:arg2 syntax. Pipes
are pure functions of their input, so the same input always renders the same output. See
Pipes.
Built-in pipes
Import the ones you use from @angular/common (or import CommonModule). Parameters follow the pipe name
separated by colons, and pipes chain left to right.
{{ createdAt | date:'medium' }} <!-- Jun 15, 2024, 9:03:01 AM -->
{{ createdAt | date:'yyyy-MM-dd':'UTC' }} <!-- format + timezone -->
{{ price | currency:'EUR':'symbol':'1.2-2' }} <!-- €1,234.50 -->
{{ ratio | percent:'1.0-1' }} <!-- 42.5% -->
{{ count | number:'1.0-0' }} <!-- 1,024 -->
{{ user | json }} <!-- debugging: pretty-printed JSON -->
{{ 'hello world' | titlecase }} <!-- Hello World -->
{{ name | uppercase }} / {{ name | lowercase }}
{{ items | slice:0:3 }} <!-- first three -->
{{ longText | slice:0:100 | titlecase }} <!-- chained -->
keyvalue turns an object or Map into an iterable of \{ key, value } entries for @for:
@for (entry of settings | keyvalue; track entry.key) {
<li>{{ entry.key }}: {{ entry.value }}</li>
}
The async pipe subscribes to an Observable or Promise, returns the latest value, and unsubscribes
automatically when the component is destroyed — the idiomatic way to render reactive data without a manual
subscription.
@if (user$ | async; as user) {
<p>Welcome, {{ user.name }}</p>
}
Reference tables: Pipes guide and
AsyncPipe. Common date/number/currency pipes live under
DatePipe,
CurrencyPipe,
DecimalPipe, and
PercentPipe.
Pure vs. impure pipes
Pipes are pure by default: Angular re-runs transform() only when the input reference changes (a new
object, not a mutated one). This makes them cheap — a pure pipe is skipped on most change-detection cycles.
An impure pipe (@Pipe(\{ name: 'x', pure: false })) runs on every change-detection cycle, regardless
of whether its inputs changed. AsyncPipe is impure because it must emit values as they arrive. Write an
impure pipe only when unavoidable, keep its work trivial, and never do I/O in one — otherwise it becomes a
performance hazard, especially under ChangeDetectionStrategy.Default (see
Lifecycle and change detection).
// Pure: recomputes only when `items` is reassigned, not when it is push()-ed into.
@Pipe({ name: 'topN' })
export class TopNPipe implements PipeTransform {
transform(items: readonly number[], n = 3): number[] {
return [...items].sort((a, b) => b - a).slice(0, n);
}
}
A custom pipe
Give @Pipe a name, implement PipeTransform.transform(value, …args), and add the pipe class to a
component’s imports. Pipes are standalone by default.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 20, trail = '…'): string {
if (value.length <= limit) {
return value;
}
return value.slice(0, limit).trimEnd() + trail;
}
}
@Component({
selector: 'app-post',
imports: [TruncatePipe],
template: '<p>{{ post().body | truncate:80 }}</p>',
})
export class Post { /* ... */ }