Tutorials Logic, IN info@tutorialslogic.com

Angular Pipes Built in Custom Pipes

Pipe Foundations

Pipes transform display values inside templates. This lesson distinguishes built-in, async, pure, impure, and custom pipes, then explains when computed state or an ordinary function is the clearer tool.

Pipe Definition

Pipes are a simple and expressive way to transform values directly inside Angular templates. They take a value as input, apply some formatting or transformation, and return the result for display. Pipes are used with the pipe operator |. Instead of changing the original data in the component class, a pipe changes how the value appears in the UI. This makes templates easier to read and keeps presentation-specific formatting logic close to where the value is displayed.

For example, a component may store a raw date object, an unformatted price, a lowercase name, or a long block of text. Pipes let the template decide how those values should be shown to the user. A date can be formatted, a number can be displayed as currency, text can be converted to uppercase, or a long sentence can be shortened. This is one of the reasons pipes are so common in Angular applications: they improve readability while reducing repeated display logic.

Pipe Benefits

  • Cleaner templates by avoiding repeated formatting code in the component.
  • Reusable display logic because the same pipe can be used in many templates.
  • Better separation of concerns because presentation formatting stays separate from business logic.
  • Readable templates since a pipe often explains intent clearly, such as currency, date, or uppercase.
  • Built-in convenience because Angular already ships with many common transformation pipes.

Pipe Syntax

The general syntax looks like this:

If the pipe needs additional options, those are passed using : after the pipe name.

Multiple pipes can also be chained together. The output of one pipe becomes the input of the next pipe.

Pipe Syntax Example

Pipe Syntax Example
{{ value | pipeName }}

Pipe with Parameters

Pipe with Parameters
{{ price | currency:'USD':'symbol':'1.2-2' }}

Chained Pipes

Chained Pipes
{{ name | uppercase | slice:0:5 }}

Built-in Transformations

Built-in Pipes

Angular includes several built-in pipes that solve common presentation needs without extra code. These are often the first pipes beginners use.

Pipe Purpose Example
DatePipe Formats date values {{ today | date:'dd/MM/yyyy' }}
UpperCasePipe Converts text to uppercase {{ name | uppercase }}
LowerCasePipe Converts text to lowercase {{ name | lowercase }}
TitleCasePipe Capitalizes words {{ title | titlecase }}
CurrencyPipe Formats numbers as currency {{ price | currency:'USD' }}
DecimalPipe Formats decimal precision {{ pi | number:'1.2-4' }}
PercentPipe Formats numbers as percentages {{ ratio | percent }}
JsonPipe Displays objects as JSON {{ data | json }}
SlicePipe Slices strings or arrays {{ items | slice:0:3 }}
AsyncPipe Subscribes to Promises or Observables {{ user$ | async }}
KeyValuePipe Turns object properties into iterable key-value pairs @for (item of obj | keyvalue; track item.key)

Built-in Pipe Usage

When using standalone Angular components, built-in pipes usually need to be imported into the component. The example below shows common pipe usage in one place.

This example shows why pipes are convenient. The raw values stay simple in the component, while the template decides how those values should appear to the user.

Built-in Pipes Usage

Built-in Pipes Usage
import { Component } from '@angular/core';
import {
    DatePipe,
    CurrencyPipe,
    UpperCasePipe,
    DecimalPipe,
    PercentPipe,
    TitleCasePipe,
    SlicePipe
} from '@angular/common';

@Component({
    selector: 'app-pipes-demo',
    standalone: true,
    imports: [DatePipe, CurrencyPipe, UpperCasePipe, DecimalPipe, PercentPipe, TitleCasePipe, SlicePipe],
    template: `
        <p>Today: {{ today | date:'fullDate' }}</p>
        <p>Short date: {{ today | date:'dd/MM/yyyy' }}</p>
        <p>Name: {{ name | uppercase }}</p>
        <p>Title: {{ title | titlecase }}</p>
        <p>Price: {{ price | currency:'USD':'symbol':'1.2-2' }}</p>
        <p>Pi: {{ pi | number:'1.3-5' }}</p>
        <p>Ratio: {{ ratio | percent:'1.0-1' }}</p>
        <p>{{ name | uppercase | slice:0:5 }}</p>
    `
})
export class PipesDemoComponent {
    today = new Date();
    name = 'tutorials logic';
    title = 'angular pipes introduction';
    price = 1234.5;
    pi = 3.14159265;
    ratio = 0.825;
}

Common Built-in Pipes

DatePipe is one of the most commonly used pipes because applications often need to display dates in user-friendly formats. You can show a full date, short date, month name, time, or a custom pattern. This is useful in dashboards, reports, blog posts, booking systems, and admin panels.

CurrencyPipe, DecimalPipe, and PercentPipe are common in e-commerce, finance, analytics, and reporting. They help make numbers readable without adding formatting logic directly in the component class.

JsonPipe is especially useful while debugging. It should not usually be treated as a final production display tool for users, but it is excellent for inspecting objects during development.

Async and Key-Value Data

AsyncPipe

The AsyncPipe deserves special attention because it behaves differently from display-only pipes. It subscribes to an Observable or Promise, returns the latest emitted value, and automatically handles cleanup when the view is destroyed. This makes it extremely useful in Angular applications that rely on RxJS or asynchronous data sources.

Without AsyncPipe, developers often subscribe manually in the component and then remember to clean up later. The async pipe reduces that boilerplate and keeps the template expressive.

AsyncPipe Example

AsyncPipe Example
import { Component } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { interval, map } from 'rxjs';

@Component({
    selector: 'app-clock',
    standalone: true,
    imports: [AsyncPipe],
    template: `
        <p>Seconds passed: {{ seconds$ | async }}</p>
    `
})
export class ClockComponent {
    seconds$ = interval(1000).pipe(
        map(value => value + 1)
    );
}

KeyValuePipe

The KeyValuePipe is useful when you need to iterate over object properties in a template. Since templates are often designed around arrays, this pipe helps convert object data into an iterable form.

KeyValuePipe Example

KeyValuePipe Example
import { Component } from '@angular/core';
import { KeyValuePipe } from '@angular/common';

@Component({
    selector: 'app-settings-view',
    standalone: true,
    imports: [KeyValuePipe],
    template: `
        @for (item of settings | keyvalue; track item.key) {
            <p>{{ item.key }}: {{ item.value }}</p>
        }
    `
})
export class SettingsViewComponent {
    settings = {
        theme: 'dark',
        language: 'English',
        notifications: true
    };
}

Custom Pipe Design

Custom Pipes

When the built-in pipes do not solve your formatting need, you can create a custom pipe. A custom pipe is declared using the @Pipe() decorator and must implement the PipeTransform interface. The main logic goes inside the transform() method.

Custom pipes are a good fit for small reusable view transformations such as truncating text, formatting labels, displaying initials, or converting status codes into readable output. If the logic becomes heavy or has side effects, it is usually better placed in a service or component method.

Custom Pipe - Truncate Text

Custom Pipe - Truncate Text
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;
    }
}

Creating a Custom Pipe

Creating a Custom Pipe
import { Component } from '@angular/core';
import { TruncatePipe } from './truncate.pipe';

@Component({
    selector: 'app-article',
    standalone: true,
    imports: [TruncatePipe],
    template: `
        <p>{{ longText | truncate }}</p>
        <p>{{ longText | truncate:20 }}</p>
        <p>{{ longText | truncate:30:' [read more]' }}</p>
    `
})
export class ArticleComponent {
    longText = 'Angular is a powerful framework for building modern web applications with TypeScript.';
}

Pure and Impure Pipes

By default, Angular pipes are pure. A pure pipe runs only when Angular detects that the input reference has changed. This makes pure pipes efficient and suitable for most formatting needs. An impure pipe, on the other hand, runs on every change detection cycle. That makes impure pipes more flexible, but also more expensive.

Beginners often hear about impure pipes in the context of filtering arrays, but this needs care. In modern Angular, filtering in the template with an impure pipe is usually not the best default choice for performance-sensitive applications.

This works, but because the pipe runs frequently, it can become expensive in larger lists. It is usually better to compute filtered results in the component or with signals so Angular recalculates only when needed.

Type Runs when Performance Typical use
Pure (default) Input reference changes Fast Formatting values for display
Impure (pure: false) Every change detection cycle Slower Rare special cases with mutable inputs

Impure Pipe Example

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

@Pipe({
    name: 'filter',
    standalone: true,
    pure: false
})
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())
        );
    }
}

Signals and Derived Values

In modern Angular, especially with signals, many transformations that might once have been written as impure pipes are now better expressed using computed(). Computed signals only recalculate when their dependencies change, which is more efficient and often easier to reason about.

This pattern is often a better fit than an impure filtering pipe because the logic stays explicit and recomputation happens only when the dependent signals actually change.

computed() Instead of Impure Pipe

computed() Instead of Impure Pipe
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' },
    ]);

    filtered = computed(() =>
        this.users().filter(u =>
            u.name.toLowerCase().includes(this.search().toLowerCase())
        )
    );
}

Pipe Decisions

Pipe or Function

Use a pipe when the logic is mainly about display formatting. For example, converting text to title case, truncating text, showing a date, formatting a price, or presenting a JSON object for debugging are all good pipe use cases.

Avoid putting heavy business logic, network calls, or mutation-driven behavior inside pipes. A pipe should not become a hidden service or a complicated data-processing layer. If the logic needs external dependencies, has side effects, or is central to application behavior rather than presentation, it usually belongs in the component, a service, or a computed signal instead.

Pipe Failures

  • Using a pipe for heavy logic that should really live in a component or service.
  • Assuming AsyncPipe is only a formatter when it actually manages subscriptions too.
  • Overusing impure pipes for filtering or sorting large data sets.
  • Forgetting to import standalone pipes when using them in standalone components.
  • Expecting a pipe to permanently change the original value instead of only changing the displayed result.

Pipe Review

Pipes are one of Angular's cleanest features for template-level transformations. They make values easier to display, keep templates expressive, and reduce formatting clutter in components. Built-in pipes handle many common needs immediately, while custom pipes let you create reusable view transformations for your own application. Once you understand when to use pure pipes, when to avoid impure ones, and when a computed signal or service is a better fit, pipes become a very practical part of Angular development.

Confirm the page outcome

Pipe Knowledge Check

5 checks
  • Pipes are a simple and expressive way to transform values directly inside Angular templates.
  • They take a value as input, apply some formatting or transformation, and return the result for display.
  • Pipes are used with the pipe operator |.
  • Instead of changing the original data in the component class, a pipe changes how the value appears in the UI.
  • This makes templates easier to read and keeps presentation-specific formatting logic close to where the value is displayed.

Pipe Design Questions

push() keeps the same array reference, and a pure pipe is allowed to reuse its previous result. Replace the array—items = [...items, newItem]—or update its signal immutably.

Each async pipe instance subscribes to the Observable it receives. With a cold HTTP Observable, two bindings can therefore trigger two requests.

An impure pipe can execute during every change-detection pass, even when the list and search text have not changed. A computed signal records those dependencies and recalculates only when one of them changes, then caches the result for repeated reads.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.