Pipes

This section documents modern, standalone Angular — signals, the built-in @if / @for / @switch control flow, @defer, typed reactive forms, provideHttpClient, functional guards and interceptors, and server-side rendering with hydration — as described by the official documentation at angular.dev, which is the reference these pages are written and verified against.

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 { /* ... */ }