Angular Pipes
Pipes transform values directly inside templates, and Angular ships a solid set of built-in ones alongside a small, well-defined API for writing your own.
What Pipes Do
A pipe takes an input value and returns a transformed output, applied in a template with the '|' syntax. Instead of formatting a date or currency value in component logic, you express the transformation right where it's displayed, which keeps templates declarative and components free of view-formatting code.
Common Built-in Pipes
- DatePipe — formats JavaScript Date values ({{ date | date:'shortDate' }}).
- CurrencyPipe — formats numbers as currency with a symbol and locale.
- UpperCasePipe / LowerCasePipe — changes string casing.
- DecimalPipe — controls the number of integer and decimal digits shown.
- PercentPipe — formats a fraction as a percentage.
- JsonPipe — pretty-prints an object, handy for debugging templates.
- AsyncPipe — subscribes to an Observable or Promise and unwraps its value.
- SlicePipe — returns a subset of an array or string.
pipe-demo.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
@Component({
selector: 'app-pipe-demo',
standalone: true,
imports: [CommonModule],
template: `
<p>{{ today | date:'fullDate' }}</p>
<p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>
<p>{{ username | uppercase }}</p>
<p>{{ ratio | percent:'1.0-1' }}</p>
`
})
export class PipeDemoComponent {
today = new Date();
price = 49.9;
username = 'ada lovelace';
ratio = 0.734;
}
bootstrapApplication(PipeDemoComponent).catch((err) => console.error(err));
Chaining and Parameterizing Pipes
Pipes accept parameters after a colon, and multiple pipes can be chained with additional '|' characters — each pipe receives the output of the one before it, evaluated left to right.
Creating a Custom Pipe
A custom pipe is a class decorated with @Pipe that implements PipeTransform. The transform() method receives the bound value plus any parameters passed after the colon, and returns the value to render. Standalone pipes are imported directly into a component's imports array, just like standalone components.
truncate.pipe.ts
import { Component, Pipe, PipeTransform } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 20, suffix = '...'): string {
if (!value) return '';
return value.length > limit ? value.slice(0, limit) + suffix : value;
}
}
@Component({
selector: 'app-root',
standalone: true,
imports: [TruncatePipe],
template: `<p>{{ text | truncate:20 }}</p>`
})
export class AppComponent {
text = 'This is a long piece of sample text used to demonstrate the truncate pipe.';
}
bootstrapApplication(AppComponent).catch((err) => console.error(err));
file-size.pipe.ts
import { Component, Pipe, PipeTransform } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit = 20, suffix = '...'): string {
if (!value) return '';
return value.length > limit ? value.slice(0, limit) + suffix : value;
}
}
@Pipe({
name: 'fileSize',
standalone: true
})
export class FileSizePipe implements PipeTransform {
transform(bytes: number, precision = 1): string {
if (!bytes) return '0 B';
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
const value = bytes / Math.pow(1024, exponent);
return `${value.toFixed(precision)} ${units[exponent]}`;
}
}
@Component({
selector: 'app-file-card',
standalone: true,
imports: [TruncatePipe, FileSizePipe],
template: `
<p>{{ description | truncate:40 }}</p>
<p>{{ sizeInBytes | fileSize:2 }}</p>
`
})
export class FileCardComponent {
description = 'This changelog entry explains what changed in the latest release.';
sizeInBytes = 3458201;
}
bootstrapApplication(FileCardComponent).catch((err) => console.error(err));
Exercise: Angular Pipes
What symbol applies a pipe to a template expression?