AngularJSPipes

Pipes in Angular

Pipes are a powerful feature in Angular that allow you to transform data directly in your templates. Instead of cluttering your component logic with formatting code, you declare how data should look in the template using the pipe operator |.

Angular pipes are pure functions — they take an input value, optionally accept parameters, and return a transformed output. They are lazy: Angular only re-evaluates a pipe when its input changes.

What Is a Pipe?

A pipe is used inside Angular template expressions with the | (pipe) character. The syntax is:

{{ value | pipeName }}
{{ value | pipeName: arg1 : arg2 }}

For example, to display a date in a human-readable format:

HTML
<!-- Without pipe -->
<p>{{ user.createdAt }}</p>
<!-- Output: 2024-01-15T09:30:00.000Z -->

<!-- With pipe -->
<p>{{ user.createdAt | date }}</p>
<!-- Output: Jan 15, 2024 -->

<!-- With pipe parameters -->
<p>{{ user.createdAt | date: 'fullDate' }}</p>
<!-- Output: Monday, January 15, 2024 -->
Why Use Pipes?

Pipes keep your component class clean by moving display logic to the template. Without pipes you would have to write formatting methods in every component that needs them. Compare these two approaches:

TS
// Without pipes — cluttered component
@Component({
  template: `<p>{{ getFormattedPrice(product.price) }}</p>`
})
export class ProductComponent {
  getFormattedPrice(price: number): string {
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD'
    }).format(price);
  }
}

// With pipes — clean and reusable
@Component({
  template: `<p>{{ product.price | currency: 'USD' }}</p>`
})
export class ProductComponent {}
Pure vs Impure Pipes

Every Angular pipe is either pure (default) or impure. This distinction is critical for performance.

Pure pipes are only re-executed when Angular detects a pure change to the input — meaning a new primitive value, or a new object/array reference. Angular can safely cache the result.

Impure pipes run on every change detection cycle, regardless of whether the input changed. Use them sparingly.

Aspect

Pure Pipe

Impure Pipe

When it runs

Only when input reference changes

Every change detection cycle

Performance

Fast — Angular caches results

Slow — runs very frequently

Mutable data

Will NOT detect in-place array/object mutation

Will detect all mutations

Default

Yes (pure: true)

No (pure: false)

Example

DatePipe, CurrencyPipe

AsyncPipe, JsonPipe

Note
For most use cases, stick with pure pipes. If you need to detect mutations inside arrays or objects, consider returning a new reference instead of making the pipe impure.
Chaining Pipes

You can chain multiple pipes together. They are applied left to right:

HTML
<!-- Chain: lowercase, then titlecase -->
<p>{{ 'HELLO WORLD' | lowercase | titlecase }}</p>
<!-- Output: Hello World -->

<!-- Chain: date then uppercase -->
<p>{{ today | date: 'MMMM' | uppercase }}</p>
<!-- Output: JANUARY -->

<!-- In @for control flow -->
@for (name of names | slice: 0 : 5; track name) {
  <li>{{ name | titlecase }}</li>
}
Pipes with Parameters

Pipes accept parameters after the pipe name, separated by colons. Multiple parameters use additional colons:

HTML
<!-- Single parameter -->
{{ 3.14159 | number: '1.2-2' }}
<!-- Output: 3.14 -->

<!-- Multiple parameters: slice(start, end) -->
{{ [1, 2, 3, 4, 5] | slice: 1 : 4 }}
<!-- Output: 2,3,4 -->

<!-- Currency with locale and symbol -->
{{ 1234.56 | currency: 'EUR' : 'symbol' : '1.0-0' }}
<!-- Output: EUR1,235 -->

<!-- Date with format and timezone -->
{{ launchDate | date: 'medium' : '+0200' }}
Using Pipes in Component Classes

Pipes are not limited to templates. You can inject and use them directly in your TypeScript component logic:

TS
import { Component } from '@angular/core';
import { DatePipe } from '@angular/common';

@Component({
  selector: 'app-report',
  standalone: true,
  imports: [DatePipe],
  providers: [DatePipe],
  template: `<p>{{ formattedDate }}</p>`,
})
export class ReportComponent {
  formattedDate: string;

  constructor(private datePipe: DatePipe) {
    const now = new Date();
    this.formattedDate = this.datePipe.transform(now, 'yyyy-MM-dd') ?? '';
  }
}
Tip
When injecting a pipe class directly, add it to the component's providers array so Angular knows how to instantiate it. For template-only usage, imports is enough.
Pipes in Standalone vs Module-Based Apps

In standalone components (Angular 14+), import the pipe directly in the component's imports array:

TS
// Standalone component
import { Component } from '@angular/core';
import { CurrencyPipe, DatePipe, UpperCasePipe } from '@angular/common';

@Component({
  selector: 'app-product',
  standalone: true,
  imports: [CurrencyPipe, DatePipe, UpperCasePipe],
  template: `
    <h2>{{ product.name | uppercase }}</h2>
    <p>{{ product.price | currency }}</p>
    <small>Listed: {{ product.listedAt | date: 'shortDate' }}</small>
  `,
})
export class ProductComponent {
  product = { name: 'laptop', price: 999.99, listedAt: new Date() };
}

TS
// Module-based app — import CommonModule (includes all built-in pipes)
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProductComponent } from './product.component';

@NgModule({
  declarations: [ProductComponent],
  imports: [CommonModule], // gives access to all built-in pipes
})
export class ProductModule {}
Common Pitfalls
  • Forgetting to import the pipe in standalone components — you'll see no transformation or a runtime error

  • Mutating an array in-place and expecting a pure pipe to re-run — Angular will not detect the change; create a new array instead

  • Using impure pipes for heavy computations — they run on every change detection cycle and can tank performance

  • Chaining too many pipes — each transformation creates a new value; consider pre-formatting in the component for complex logic

  • Passing wrong argument types — e.g. passing a plain string to DatePipe when it expects a Date object, number, or ISO string

Warning
Never use impure pipes for expensive operations like HTTP calls or complex sorting. Use them only when you genuinely need to react to mutable data, and even then, prefer immutable patterns.
Summary

Pipes are one of Angular's most elegant features:

  • Transform data in the template without polluting component logic
  • Chainable with | and parameterizable with :
  • Pure by default — efficient and cacheable
  • Built-in pipes (DatePipe, CurrencyPipe, etc.) cover most needs
  • Custom pipes are easy to write for domain-specific transformations

Next up: explore the full set of Built-in Pipes Angular provides out of the box.