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.
On this page · 6 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
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#
{{ 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#
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';
}
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#
- titlecase capitalises each word of the name.
- currency formats with the ₹ symbol; the digits argument 1.0-0 rounds to whole rupees.
- number:"1.1-2" shows 1 to 2 decimal places; percent turns 0.15 into 15%.
- date formats with a pattern; the custom timeAgo pipe receives an extra argument (now).
- slice cuts the notes to 20 characters.
- 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#
“No pipe found with name currency” means CurrencyPipe is missing from imports.
A pure pipe does not re-run when you push into the same array. Create a new array.
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?
Show solution
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#
What is shown for {{ 0.075 | percent:"1.1-1" }}?
Want more? Practise all Angular MCQs · Angular interview questions
My notes#
Saved in this browser.