Angular · Components

Pipes

Pipes format values in templates: a Date becomes “28 Oct 2026”, 1499.5 becomes “₹1,499.50”. Write {{ value | pipeName }} and the template stays clean.

Intermediate 6 min Lesson 13 of 38Examples target Angular 20 with standalone components. Each lesson states the version it was verified against.
Before you start:Templates
0/38 in Angular
On this page · 6 min · Intermediate

Learning objectives#

  • Use built-in pipes with arguments
  • Chain pipes
  • Use the async and json pipes
  • Write a custom pipe and understand pure pipes

Explanation#

Built-in pipes from @angular/common: date, currency, number (decimal), percent, uppercase, lowercase, titlecase, slice, json, keyvalue and async. Import the ones you use.

Arguments follow colons: {{ price | currency:'INR':'symbol':'1.0-0' }}, {{ when | date:'d MMM y, h:mm a' }}.

Chain pipes left to right: {{ name | slice:0:10 | uppercase }}.

async subscribes to an Observable or Promise and shows the latest value, unsubscribing automatically. json is great for debugging: {{ data | json }}.

Custom pipes implement PipeTransform with a transform(value, ...args) method. Pipes are pure by default: they re-run only when the input reference changes, which keeps them fast.

Syntax#

HTML Illustrative
{{ total | currency:'INR' }}
{{ createdAt | date:'mediumDate' }}
{{ 0.256 | percent:'1.0-1' }}
{{ title | titlecase }}
{{ orders$ | async }}

Code example: Built-in pipes and a custom "time ago" pipe#

TypeScriptorder-row.ts Illustrative
import { Component, Pipe, PipeTransform } from '@angular/core';
import { CurrencyPipe, DatePipe, DecimalPipe, PercentPipe, SlicePipe, TitleCasePipe } from '@angular/common';


@Pipe({ name: 'timeAgo' })
export class TimeAgoPipe implements PipeTransform {
  transform(value: Date, now: Date = new Date()): string {
    const minutes = Math.floor((now.getTime() - value.getTime()) / 60000);
    if (minutes < 1) return 'just now';
    if (minutes < 60) return `${minutes} min ago`;
    const hours = Math.floor(minutes / 60);
    if (hours < 24) return `${hours} h ago`;
    return `${Math.floor(hours / 24)} d ago`;
  }
}


@Component({
  selector: 'app-order-row',
  imports: [CurrencyPipe, DatePipe, DecimalPipe, PercentPipe, SlicePipe, TitleCasePipe, TimeAgoPipe],
  template: `
    <p>{{ customer | titlecase }}</p>
    <p>{{ total | currency: 'INR' }} · {{ total | currency: 'INR' : 'symbol' : '1.0-0' }}</p>
    <p>Weight: {{ weightKg | number: '1.1-2' }} kg</p>
    <p>Discount: {{ discount | percent }}</p>
    <p>Placed {{ placedAt | date: 'd MMM y, h:mm a' }} ({{ placedAt | timeAgo: now }})</p>
    <p>{{ notes | slice: 0 : 20 }}…</p>
  `,
})
export class OrderRow {
  customer = 'asha rao';
  total = 1499.5;
  weightKg = 2.3456;
  discount = 0.15;
  now = new Date(2026, 9, 28, 12, 0);
  placedAt = new Date(2026, 9, 28, 9, 30);
  notes = 'Please deliver after 6 pm, call before arriving';
}
Expected output
Asha Rao
₹1,499.50 · ₹1,500
Weight: 2.35 kg
Discount: 15%
Placed 28 Oct 2026, 9:30 AM (2 h ago)
Please deliver after…

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. titlecase capitalises each word of the name.
  2. currency formats with the ₹ symbol; the digits argument 1.0-0 rounds to whole rupees.
  3. number:"1.1-2" shows 1 to 2 decimal places; percent turns 0.15 into 15%.
  4. date formats with a pattern; the custom timeAgo pipe receives an extra argument (now).
  5. slice cuts the notes to 20 characters.
  6. Every pipe used is listed in the component’s imports.

Real-world use case#

An international shop sets the app locale and uses currency, date and number pipes everywhere, so prices and dates appear correctly for each country without changing component code.

Common mistakes#

Pipe not imported

“No pipe found with name currency” means CurrencyPipe is missing from imports.

Mutating arrays passed to a pure pipe

A pure pipe does not re-run when you push into the same array. Create a new array.

Heavy work in impure pipes

pure: false pipes run on every change detection. Use computed signals instead.

Best practices#

  • Format in templates with pipes, not in services
  • Keep custom pipes pure and fast
  • Use async to avoid manual subscriptions
  • Set the locale for correct formats

Remember this#

{{ value | pipe:arg1:arg2 }}.

Chain: | slice:0:10 | uppercase.

Pure pipes re-run only when the input reference changes.

Practice exercise#

Your task: Write a pipe "initials" that turns "Asha Rao" into "AR", and use it in a template.

Need a hint?
value.split(" ").map(w => w[0]).join("").toUpperCase().
Show solution
TypeScript Illustrative
import { Component, Pipe, PipeTransform } from '@angular/core';


@Pipe({ name: 'initials' })
export class InitialsPipe implements PipeTransform {
  transform(value: string): string {
    return value.split(' ').filter(Boolean).map(w => w[0]).join('').toUpperCase();
  }
}


@Component({
  selector: 'app-avatar',
  imports: [InitialsPipe],
  template: `<span class="avatar">{{ name | initials }}</span>`,   // AR
})
export class Avatar {
  name = 'Asha Rao';
}

Mini quiz#

Pipes quizPredict the output Question 1 of 3

What is shown for {{ 0.075 | percent:"1.1-1" }}?

Score so far: 0/0

Want more? Practise all Angular MCQs · Angular interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.