Introduction to Pipes in Angular

Angular is known for its clean, declarative templates and powerful data-binding system. One of the most elegant features that enhances template readability is Pipes.

Pipes are a fundamental feature in Angular used for transforming data directly in templates. They help format data before displaying it to the user — without changing the underlying component logic.

In this post, you’ll learn what pipes are, why they are useful, how to use built-in pipes, and how to create custom pipes for your own data transformations.

1. What Are Pipes in Angular?

A pipe in Angular takes in data as input and transforms it into a desired output format for display in the template.

They are defined using the pipe (|) operator in template expressions.

Example:

<p>{{ title | uppercase }}</p>

If the title variable contains "angular tutorial", the pipe transforms it to "ANGULAR TUTORIAL".

In this example, uppercase is a built-in Angular pipe that converts all characters of a string to uppercase.


2. Why Use Pipes?

Without pipes, you’d have to handle all formatting logic inside the component’s TypeScript file, making your code messy and repetitive.

For example, if you want to display a formatted date or currency in multiple places, you would need helper functions for each transformation.

Pipes eliminate this redundancy by allowing transformations directly in the HTML template, keeping your components clean and focused only on data logic.

Example Without Pipe:

@Component({
  selector: 'app-date-example',
  template: &lt;p&gt;{{ formattedDate }}&lt;/p&gt;
})
export class DateExampleComponent implements OnInit {
  formattedDate: string = '';

  ngOnInit() {
const date = new Date();
this.formattedDate = date.toDateString();
} }

Example With Pipe:

<p>{{ today | date:'fullDate' }}</p>

No extra logic is needed in the TypeScript file. Angular’s DatePipe takes care of formatting automatically.


3. How Pipes Work Under the Hood

When Angular renders a template, it checks for any expressions containing the pipe (|) operator. The pipe expression has two parts:

  1. The input data — for example, title
  2. The pipe name — for example, uppercase

Angular executes the pipe’s transformation function during change detection and displays the result.

A single pipe transforms data one way — from model to view. Pipes are pure functions by default, meaning they only re-run when their input data changes.


4. Syntax of a Pipe in a Template

The general syntax is:

{{ value | pipeName:parameter1:parameter2 }}

Example with Multiple Parameters:

<p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>

Here:

  • currency is the pipe name.
  • 'USD', 'symbol', and '1.2-2' are parameters for customization.

5. Types of Pipes in Angular

Angular has two main categories of pipes:

1. Built-in Pipes

Provided by Angular out of the box — such as DatePipe, CurrencyPipe, UpperCasePipe, LowerCasePipe, PercentPipe, DecimalPipe, and AsyncPipe.

2. Custom Pipes

Created by developers to perform specific transformations that are not available among built-in pipes.


6. Common Built-in Pipes

UpperCasePipe

Converts text to uppercase.

<p>{{ 'angular' | uppercase }}</p>

Output: ANGULAR


LowerCasePipe

Converts text to lowercase.

<p>{{ 'ANGULAR' | lowercase }}</p>

Output: angular


TitleCasePipe

Capitalizes the first letter of each word.

<p>{{ 'learn angular pipes' | titlecase }}</p>

Output: Learn Angular Pipes


DatePipe

Formats date objects or timestamps.

<p>{{ today | date:'fullDate' }}</p>

Output: Wednesday, October 9, 2025

You can use formats like:

  • 'shortDate' → 10/9/25
  • 'mediumDate' → Oct 9, 2025
  • 'longDate' → October 9, 2025

CurrencyPipe

Formats numbers as currency values.

<p>{{ price | currency:'USD' }}</p>

Output: $99.00

You can customize:

<p>{{ price | currency:'EUR':'symbol':'1.0-0' }}</p>

Output: €99


DecimalPipe

Formats decimal numbers.

<p>{{ 3.14159 | number:'1.2-3' }}</p>

Output: 3.142


PercentPipe

Displays numeric values as percentages.

<p>{{ 0.75 | percent }}</p>

Output: 75%


AsyncPipe

Automatically subscribes to an Observable or Promise and returns the latest emitted value.

<p>{{ userData$ | async }}</p>

It handles subscription and unsubscription automatically, making it ideal for reactive programming.


7. Chaining Multiple Pipes

You can combine multiple pipes to create complex transformations in one line.

Example:

<p>{{ user.name | uppercase | slice:0:10 }}</p>
  • uppercase converts the name to uppercase.
  • slice:0:10 limits it to the first 10 characters.

Output: If user.name = 'JonathanDoe', the result is JONATHAND.


8. Using Pipes with Parameters

Many pipes accept parameters to modify their behavior. Parameters are passed after a colon (:).

Example:

<p>{{ 1234.5678 | number:'1.0-2' }}</p>

Output: 1,234.57

Here:

  • 1.0 → at least one integer digit.
  • -2 → up to two decimal places.

9. Creating a Custom Pipe

Angular allows you to create custom pipes using the @Pipe decorator and implementing the PipeTransform interface.

Example: Capitalize First Letter Pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'capitalize'
})
export class CapitalizePipe implements PipeTransform {
  transform(value: string): string {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
} }

Use it in a component:

<p>{{ 'angular' | capitalize }}</p>

Output: Angular


10. Passing Parameters to a Custom Pipe

You can also make your custom pipes dynamic by accepting arguments.

Example: Repeat Text Pipe

@Pipe({ name: 'repeat' })
export class RepeatPipe implements PipeTransform {
  transform(value: string, times: number): string {
return value.repeat(times);
} }

Usage:

<p>{{ 'Hi ' | repeat:3 }}</p>

Output: Hi Hi Hi


11. Pure vs Impure Pipes

By default, Angular pipes are pure, meaning they execute only when their input changes.

Pure Pipe Example

@Pipe({ name: 'pureExample', pure: true })

Pure pipes are efficient and suitable for most use cases.

Impure Pipe Example

@Pipe({ name: 'impureExample', pure: false })

Impure pipes run on every change detection cycle, which can impact performance.
Use them only when working with mutable objects or collections that frequently change.


12. Example of an Impure Pipe

@Pipe({ name: 'filter', pure: false })
export class FilterPipe implements PipeTransform {
  transform(items: any[], searchText: string): any[] {
if (!items || !searchText) return items;
return items.filter(item =&gt;
  item.toLowerCase().includes(searchText.toLowerCase())
);
} }

Template usage:

<li *ngFor="let name of names | filter:searchText">{{ name }}</li>

This pipe filters a list based on user input dynamically.


13. Benefits of Using Pipes

  1. Cleaner Templates
    Pipes allow formatting and transformation directly in templates, avoiding clutter in TypeScript files.
  2. Reusability
    A pipe can be used in multiple components throughout the app.
  3. Separation of Concerns
    Data logic stays in pipes, while UI logic remains in components.
  4. Improved Readability
    Templates are easier to read and maintain when transformation logic is simplified using pipes.

14. When Not to Use Pipes

Avoid using pipes when:

  • The transformation is complex or computationally heavy.
  • You’re modifying large data sets frequently (e.g., filtering big arrays).
  • You need backend-side transformations (pipes are only for display, not actual data manipulation).

For large operations, perform transformations in the component or service layer.


15. Using Pipes in Components and Modules

Every pipe must be declared in an Angular module before it can be used.

Example:

@NgModule({
  declarations: [
AppComponent,
CapitalizePipe,
RepeatPipe
], bootstrap: [AppComponent] }) export class AppModule {}

16. AsyncPipe in Depth

AsyncPipe is one of the most powerful Angular pipes. It automatically handles Observables and Promises.

Example with Observable:

@Component({
  selector: 'app-users',
  template: `
&lt;ul&gt;
  &lt;li *ngFor="let user of users$ | async"&gt;{{ user.name }}&lt;/li&gt;
&lt;/ul&gt;
` }) export class UsersComponent { users$ = this.http.get<any[]>('https://jsonplaceholder.typicode.com/users'); constructor(private http: HttpClient) {} }

The AsyncPipe eliminates the need for manual subscribe() and unsubscribe() calls.


17. Combining Pipes for Custom Output

You can chain pipes to create powerful transformations.

Example:

<p>{{ 'angular pipes tutorial' | titlecase | slice:0:15 }}</p>

First, the text is transformed to Angular Pipes Tutorial, and then truncated to the first 15 characters:
Angular Pipes T


18. Pipe Performance Considerations

  • Pure pipes are cached and optimized.
  • Impure pipes can slow down performance because they run frequently.
  • Avoid using impure pipes on large lists or inside *ngFor loops.

If a pipe causes performance issues, consider using memoization or performing transformations in the component instead.


19. Testing a Pipe

Testing ensures your pipes work as expected.

Example:

import { CapitalizePipe } from './capitalize.pipe';

describe('CapitalizePipe', () => {
  const pipe = new CapitalizePipe();

  it('transforms "angular" to "Angular"', () => {
expect(pipe.transform('angular')).toBe('Angular');
}); it('returns empty string for null input', () => {
expect(pipe.transform(null as any)).toBe('');
}); });

20. Real-World Example: Formatting User Data

Imagine you have a user list and want to display names in title case, registration dates formatted, and balance in currency.

Component Template:

<div *ngFor="let user of users">
  <p>{{ user.name | titlecase }}</p>
  <p>{{ user.registered | date:'mediumDate' }}</p>
  <p>{{ user.balance | currency:'USD' }}</p>
</div>

The pipes handle all data transformations elegantly, without extra logic in the TypeScript class.


21. Global vs Local Pipes

Pipes can be used globally (declared in the root module) or locally (declared in a feature module).

If a pipe is used only in one feature module, declare it locally to avoid unnecessary imports in other parts of the app.


22. Localization Support in Pipes

Angular pipes like CurrencyPipe, DatePipe, and DecimalPipe are locale-aware. You can configure localization by setting the locale in your app module.

Example:

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';

registerLocaleData(localeFr);

This ensures your dates, currencies, and numbers format according to French locale settings.


23. Reusable Utility Pipes

You can create reusable utility pipes like:

  • TruncatePipe → shorten long text
  • FilterPipe → filter lists
  • SortPipe → sort arrays
  • SearchPipe → search text within data

These small reusable pipes enhance productivity across large applications.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *