# Pipes

Course: [Angular](https://www.devtutorials.ai/learn/angular) · Section: Core Angular Concepts
Source: https://www.devtutorials.ai/learn/angular/core-concepts/pipes

> What pipes are and why to use them, the built-in date, currency, number, percent, case and json pipes, chaining pipes, pipe parameters, and writing a custom pipe.

## What Are Pipes?

A **pipe** is a function that formats a value inside a template, without changing the value stored in the class. You apply a pipe with the `|` character: `{{ value | pipeName }}`.

The value on the left goes into the pipe. The pipe returns the formatted text, and Angular displays that text.

### Real-World Example

An orders API returns `createdAt: "2026-03-15T09:30:00Z"` and `total: 54999`. The orders table must show **15 Mar 2026** and **₹54,999.00**.

Pipes do this formatting in the template, so the component keeps the raw API values for sorting, filtering and calculations.

<figure className="ngc-fig">
<svg viewBox="0 0 640 155" role="img" aria-label="The value 54999 goes through the currency pipe and is displayed as ₹54,999.00. The class value does not change.">
<defs><marker id="ngc-d2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" className="ngc-arrowhead" /></marker></defs><g className="ngc-node ngc-soft c-purple"><rect x="10" y="50" width="170" height="60" rx="9" /><text x="95.0" y="78" textAnchor="middle" style={{fontSize:"17px"}}>54999</text><text className="ngc-sub" x="95.0" y="96" textAnchor="middle">value in the class</text></g><g className="ngc-pulse"><g className="ngc-node ngc-solid c-orange"><rect x="235" y="50" width="170" height="60" rx="9" /><text x="320.0" y="77" textAnchor="middle" style={{fontSize:"14px"}}>| currency: 'INR'</text><text className="ngc-sub" x="320.0" y="95" textAnchor="middle">the pipe</text></g></g><g className="ngc-node ngc-soft c-green"><rect x="460" y="50" width="170" height="60" rx="9" /><text x="545.0" y="78" textAnchor="middle" style={{fontSize:"17px"}}>₹54,999.00</text><text className="ngc-sub" x="545.0" y="96" textAnchor="middle">text on screen</text></g><line className="ngc-link ngc-flow c-orange" x1="182" y1="80" x2="233" y2="80" markerEnd="url(#ngc-d2)" /><line className="ngc-link ngc-flow c-green" x1="407" y1="80" x2="458" y2="80" markerEnd="url(#ngc-d2)" /><text className="ngc-note" x="320" y="140" textAnchor="middle">The class still stores 54999, so calculations stay correct.</text>
</svg>
<figcaption>A pipe formats the value on its way to the screen.</figcaption>
</figure>

## Why Pipes?

Without pipes, every component would need its own formatting methods, such as `formatDate()` and `formatPrice()`. That code is repeated across the app and easy to get wrong.

Pipes solve this:

- **Reusable.** One pipe formats values in every template of the app.
- **Raw data stays raw.** The class keeps numbers and dates, so calculations stay correct.
- **Locale-aware.** Built-in pipes follow the app's locale for dates, currencies and number separators.
- **Fast.** By default, Angular runs a pipe again only when its input value changes.
- **Readable.** `{{ total | currency:'INR' }}` states its purpose clearly in the template.

## Built-in Pipes

Angular ships common pipes in `@angular/common`. Import each pipe you use into the component's `imports` list.

| Pipe | Template name | Example input | Example output |
|---|---|---|---|
| `DatePipe` | `date` | `'2026-03-15'` | `Mar 15, 2026` |
| `CurrencyPipe` | `currency` | `54999` | `$54,999.00` |
| `DecimalPipe` | `number` | `1234.5` | `1,234.5` |
| `PercentPipe` | `percent` | `0.256` | `26%` |
| `UpperCasePipe` | `uppercase` | `'angular'` | `ANGULAR` |
| `LowerCasePipe` | `lowercase` | `'ANGULAR'` | `angular` |
| `TitleCasePipe` | `titlecase` | `'order shipped'` | `Order Shipped` |
| `JsonPipe` | `json` | `{ id: 7 }` | `{ "id": 7 }` |

The examples on this page use the default `en-US` locale, so numbers use western grouping: `1,284,503`. To use Indian grouping (`12,84,503`) and Indian date formats, register the `en-IN` locale data with `registerLocaleData` and provide `LOCALE_ID` in `app.config.ts`.

### DatePipe

`DatePipe` formats a date, a timestamp or an ISO date string. Pass a format name or a pattern as a parameter.

```angular runnable title="DatePipe formats one date in several ways"
import { Component } from '@angular/core';
import { DatePipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [DatePipe],
  template: `
    <p>Default: {{ orderDate | date }}</p>
    <p>Short: {{ orderDate | date: 'shortDate' }}</p>
    <p>Custom: {{ orderDate | date: 'dd MMM yyyy' }}</p>
    <p>Full: {{ orderDate | date: 'fullDate' }}</p>
  `,
})
export class App {
  orderDate = new Date(2026, 2, 15);
}
```

Common pattern letters are `dd` (day), `MMM` (short month name), `MM` (month number), `yyyy` (year), `HH:mm` (24-hour time) and `h:mm a` (12-hour time).

### CurrencyPipe

`CurrencyPipe` formats a number as money. The first parameter is the ISO currency code, such as `'INR'`, `'USD'` or `'EUR'`.

```angular runnable title="CurrencyPipe formats prices in different currencies"
import { Component } from '@angular/core';
import { CurrencyPipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [CurrencyPipe],
  template: `
    <p>Default: {{ price | currency }}</p>
    <p>Rupees: {{ price | currency: 'INR' }}</p>
    <p>Euros: {{ price | currency: 'EUR' }}</p>
    <p>No decimals: {{ price | currency: 'INR' : 'symbol' : '1.0-0' }}</p>
  `,
})
export class App {
  price = 54999;
}
```

### DecimalPipe

`DecimalPipe`, used as `number`, adds thousands separators and controls decimal places. Its parameter has the form `'minInteger.minFraction-maxFraction'`.

```angular runnable title="DecimalPipe controls separators and decimal places"
import { Component } from '@angular/core';
import { DecimalPipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [DecimalPipe],
  template: `
    <p>Page views: {{ views | number }}</p>
    <p>Rating: {{ rating | number: '1.1-1' }}</p>
    <p>Distance: {{ distance | number: '1.2-2' }} km</p>
  `,
})
export class App {
  views = 1284503;
  rating = 4.4666;
  distance = 7.5;
}
```

`'1.2-2'` means: at least 1 digit before the decimal point, and exactly 2 digits after it.

### PercentPipe

`PercentPipe` multiplies a number by 100 and adds a percent sign. It accepts the same digit format as `DecimalPipe`.

```angular runnable title="PercentPipe turns ratios into percentages"
import { Component } from '@angular/core';
import { PercentPipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [PercentPipe],
  template: `
    <p>Conversion rate: {{ conversion | percent }}</p>
    <p>Test coverage: {{ coverage | percent: '1.1-1' }}</p>
  `,
})
export class App {
  conversion = 0.256;
  coverage = 0.8734;
}
```

### UpperCasePipe, LowerCasePipe and TitleCasePipe

These three pipes change the letter case of text.

- `uppercase` changes every letter to a capital letter.
- `lowercase` changes every letter to a small letter.
- `titlecase` capitalises the first letter of each word.

```angular runnable title="Case pipes normalise text from an API"
import { Component } from '@angular/core';
import { LowerCasePipe, TitleCasePipe, UpperCasePipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [UpperCasePipe, LowerCasePipe, TitleCasePipe],
  template: `
    <p>Coupon code: {{ coupon | uppercase }}</p>
    <p>Email: {{ email | lowercase }}</p>
    <p>Status: {{ status | titlecase }}</p>
  `,
})
export class App {
  coupon = 'save20now';
  email = 'Asha.Kumar@Example.COM';
  status = 'out for delivery';
}
```

### JsonPipe

`JsonPipe` converts an object to formatted JSON text. Developers use it to inspect data while debugging a template.

```angular runnable title="JsonPipe prints an object for debugging"
import { Component } from '@angular/core';
import { JsonPipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [JsonPipe],
  template: `<pre>{{ user | json }}</pre>`,
})
export class App {
  user = { id: 42, name: 'Ravi', roles: ['editor', 'reviewer'] };
}
```

Wrap `json` output in a `<pre>` element. `<pre>` keeps the line breaks and indentation, so nested objects stay readable.

## Chaining Pipes

You can apply several pipes to one value by writing them one after another. This is called **chaining**. Angular runs the pipes from left to right, and each pipe receives the output of the previous one.

```angular runnable title="Chained pipes run from left to right"
import { Component } from '@angular/core';
import { DatePipe, UpperCasePipe } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [DatePipe, UpperCasePipe],
  template: `
    <p>Delivery: {{ deliveryDate | date: 'EEEE, d MMMM' | uppercase }}</p>
  `,
})
export class App {
  deliveryDate = new Date(2026, 2, 18);
}
```

First `date` produces `Wednesday, 18 March`. Then `uppercase` produces `WEDNESDAY, 18 MARCH`.

The order matters. `{{ name | uppercase | slice: 0 : 3 }}` is valid, but putting a date pipe after `uppercase` fails, because `uppercase` returns text that is no longer a date.

## Pipe Parameters

A **pipe parameter** changes how a pipe formats its value. You write a colon after the pipe name, then the parameter value. Separate several parameters with more colons.

```html
{{ value | pipeName : parameter1 : parameter2 }}
```

| Example | Pipe | Parameters |
|---|---|---|
| `{{ d \| date: 'shortTime' }}` | `date` | format |
| `{{ p \| currency: 'INR' : 'code' }}` | `currency` | currency code, display style |
| `{{ n \| number: '1.0-2' }}` | `number` | digit format |
| `{{ text \| slice: 0 : 20 }}` | `slice` | start index, end index |

Parameters can also be expressions from the class, such as `{{ price | currency: selectedCurrency }}`. When `selectedCurrency` changes, the pipe runs again.

## Custom Pipes

A **custom pipe** is your own formatting function, packaged so every template can use it.

You create one with the `@Pipe` decorator and a class that has a `transform` method. Angular calls `transform` with the value from the left side of `|`, followed by any parameters. In a project, the CLI creates the file for you:

```bash
ng generate pipe file-size
```

```angular runnable title="A custom pipe formats file sizes"
import { Component, Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'fileSize' })
export class FileSizePipe implements PipeTransform {
  transform(bytes: number, decimals: number = 1): string {
    if (bytes < 1024) return bytes + ' B';
    const units = ['KB', 'MB', 'GB'];
    let size = bytes / 1024;
    let unit = 0;
    while (size >= 1024 && unit < units.length - 1) {
      size = size / 1024;
      unit++;
    }
    return size.toFixed(decimals) + ' ' + units[unit];
  }
}

@Component({
  selector: 'app-root',
  imports: [FileSizePipe],
  template: `
    @for (file of files; track file.name) {
      <p>{{ file.name }}: {{ file.bytes | fileSize }}</p>
    }
    <p>Precise: {{ 5368709120 | fileSize: 2 }}</p>
  `,
})
export class App {
  files = [
    { name: 'notes.txt', bytes: 820 },
    { name: 'photo.jpg', bytes: 2457600 },
    { name: 'backup.zip', bytes: 1610612736 },
  ];
}
```

A custom pipe has three parts:

1. `@Pipe({ name: 'fileSize' })` sets the name used in templates.
2. `implements PipeTransform` declares that the class has a `transform` method.
3. `transform(value, ...params)` returns the formatted result.

Custom pipes are **pure** by default. Angular runs a pure pipe again only when its input value or a parameter changes. This keeps templates fast. Keep `transform` free of side effects, so the same input always gives the same output.

## Common Mistakes

<div className="ngc-mistakes">

| Mistake | What you see | Fix |
|---|---|---|
| Pipe not imported | `NG0302: The pipe 'date' could not be found` | Add `DatePipe` (or the pipe you use) to `imports` |
| Using the class name in the template | `{{ d \| DatePipe }}` is not found | Use the template name: `{{ d \| date }}` |
| Spaces in the digit format | `'1.2 - 2'` causes a format error | Write it without spaces: `'1.2-2'` |
| `percent` on a whole number | `25` shows as `2,500%` | Pass a ratio: `0.25` |
| Chaining in the wrong order | A pipe receives text it cannot read | Put pipes that need raw values first |
| Formatting in the class instead | Duplicated formatting code in many components | Move the formatting into a pipe |

</div>

## Check Yourself

## Exercises

## What to Remember

- A pipe formats a value for display with `{{ value | pipe }}` and leaves the class data unchanged.
- Built-in pipes cover dates, currency, numbers, percentages, letter case and JSON. Pass settings with `:` and chain pipes from left to right.
- A custom pipe is a class with `@Pipe` and a `transform` method.

Next: **Event Handling**, how to respond to clicks, key presses and form changes.
