Angular Pipes
What are Pipes?
Pipes are a simple way to transform values in Angular templates. They take data as input, transform it, and display the result. Pipes are used with the pipe operator | in templates. Angular provides many built-in pipes and you can also create custom pipes.
Built-in Pipes
Angular provides the following built-in pipes out of the box:
| Pipe | Usage | Example |
|---|---|---|
DatePipe | Formats a date value | {{ today | date:'dd/MM/yyyy' }} |
UpperCasePipe | Transforms text to uppercase | {{ name | uppercase }} |
LowerCasePipe | Transforms text to lowercase | {{ name | lowercase }} |
CurrencyPipe | Formats a number as currency | {{ price | currency:'USD' }} |
DecimalPipe | Formats a number with decimal points | {{ pi | number:'1.2-4' }} |
PercentPipe | Formats a number as a percentage | {{ ratio | percent }} |
JsonPipe | Converts a value to JSON string | {{ data | json }} |
SlicePipe | Slices an array or string | {{ items | slice:0:3 }} |
AsyncPipe | Subscribes to Observable/Promise | {{ data$ | async }} |
KeyValuePipe | Iterates over object key-value pairs | @for (item of obj | keyvalue; track item.key) |
Using Built-in Pipes
Pipes are applied in templates using the | operator. You can chain multiple pipes and pass parameters using :.
import { Component } from '@angular/core';
import { DatePipe, CurrencyPipe, UpperCasePipe, DecimalPipe } from '@angular/common';
@Component({
selector: 'app-pipes-demo',
standalone: true,
imports: [DatePipe, CurrencyPipe, UpperCasePipe, DecimalPipe],
template: `
<p>Today: {{ today | date:'fullDate' }}</p>
<p>Short date: {{ today | date:'dd/MM/yyyy' }}</p>
<p>Name: {{ name | uppercase }}</p>
<p>Price: {{ price | currency:'USD':'symbol':'1.2-2' }}</p>
<p>Pi: {{ pi | number:'1.3-5' }}</p>
<!-- Chaining pipes -->
<p>{{ name | uppercase | slice:0:5 }}</p>
`
})
export class PipesDemoComponent {
today = new Date();
name = 'tutorials logic';
price = 1234.5;
pi = 3.14159265;
}
Creating a Custom Pipe
You can create your own pipes using the @Pipe() decorator. A pipe class must implement the PipeTransform interface and define a transform() method. In Angular 21, pipes are standalone by default.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 50, ellipsis = '...'): string {
if (!value) return '';
if (value.length <= limit) return value;
return value.substring(0, limit) + ellipsis;
}
}
// Generate with CLI: ng generate pipe truncate
import { Component } from '@angular/core';
import { TruncatePipe } from './truncate.pipe';
@Component({
selector: 'app-article',
standalone: true,
imports: [TruncatePipe],
template: `
<!-- Default: 50 chars -->
<p>{{ longText | truncate }}</p>
<!-- Custom limit: 20 chars -->
<p>{{ longText | truncate:20 }}</p>
<!-- Custom ellipsis -->
<p>{{ longText | truncate:30:' [read more]' }}</p>
`
})
export class ArticleComponent {
longText = 'Angular is a powerful framework for building modern web applications with TypeScript.';
}
Pure vs Impure Pipes
By default, all pipes are pure — they only re-execute when the input value reference changes. An impure pipe re-executes on every change detection cycle. Use impure pipes sparingly as they can impact performance.
| Type | Re-runs when | Performance | Use case |
|---|---|---|---|
| Pure (default) | Input reference changes | Fast | Most transformations |
Impure (pure: false) | Every change detection cycle | Slower | Filtering arrays, async data |
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter',
standalone: true,
pure: false // impure — re-runs on every change detection
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string, field: string): any[] {
if (!items || !searchText) return items;
return items.filter(item =>
item[field]?.toLowerCase().includes(searchText.toLowerCase())
);
}
}
// Usage in template:
// <div *ngFor="let user of users | filter:searchTerm:'name'">
// Note: prefer computed() signals for filtering in Angular 21
Pipes with Signals (Angular 21)
In Angular 21, the recommended approach for transformations is to use computed() signals instead of impure pipes. Computed signals are more efficient because they only recalculate when their signal dependencies change, not on every change detection cycle.
import { Component, signal, computed } from '@angular/core';
interface User { id: number; name: string; role: string; }
@Component({
selector: 'app-user-list',
standalone: true,
template: `
<input (input)="search.set($any($event.target).value)" placeholder="Search users..." />
<p>Showing {{ filtered().length }} of {{ users().length }} users</p>
@for (user of filtered(); track user.id) {
<div>{{ user.name }} — {{ user.role }}</div>
}
`
})
export class UserListComponent {
search = signal('');
users = signal<User[]>([
{ id: 1, name: 'Alice', role: 'Admin' },
{ id: 2, name: 'Bob', role: 'Developer' },
{ id: 3, name: 'Charlie', role: 'Designer' },
]);
// computed() is more efficient than an impure pipe
filtered = computed(() =>
this.users().filter(u =>
u.name.toLowerCase().includes(this.search().toLowerCase())
)
);
}
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.