How to Use the Angular Pipe Function for Data Transformation: A Complete Guide

Angular pipes transform data directly in templates by implementing the PipeTransform interface and using the @Pipe decorator to register a transform method that accepts a value and optional arguments.

The angular pipe function for data transformation provides a declarative way to format values in templates without cluttering component logic. In the angular/angular repository, pipes are implemented as classes that adhere to a strict interface contract, enabling the framework to execute them efficiently during change detection. Understanding the underlying source code reveals how to build performant, reusable data transformation logic.

What Is the Angular Pipe Function?

An Angular pipe is a TypeScript class that implements the PipeTransform interface. This interface defines a single method, transform, which receives the input value and any number of optional arguments, returning the transformed result.

The contract is defined in [packages/core/src/change_detection/pipe_transform.ts](https://github.com/angular/angular/blob/main/packages/core/src/change_detection/pipe_transform.ts):

export interface PipeTransform {
  /**
   * Called by Angular to transform an input value to a new value.
   * @param value The value to transform.
   * @param args Additional optional arguments.
   */
  transform(value: any, ...args: any[]): any;
}

To register a class as a pipe, apply the @Pipe decorator with a configuration object containing the name property. This metadata allows the Angular compiler to recognize pipe expressions in templates.

How the Angular Pipe Function Works Under the Hood

The PipeTransform Interface Contract

Every pipe must satisfy the PipeTransform contract. The transform method acts as the entry point during template evaluation. When the compiler encounters an expression like {{ value | myPipe:arg1 }}, it generates instructions to instantiate the pipe class and invoke transform with value and arg1.

Runtime Execution and Change Detection

The runtime execution logic resides in [packages/core/src/render3/pipe.ts](https://github.com/angular/angular/blob/main/packages/core/src/render3/pipe.ts). During change detection, the framework retrieves the pipe instance from the LView (logical view) and calls the transform method. The implementation guards against null or undefined values to prevent runtime errors.

The runtime respects the pure flag defined in the @Pipe metadata. By default, pipes are pure (pure: true), meaning Angular executes the transform method only when the input value or arguments change. This enables aggressive memoization and change-detection optimizations. Impure pipes (pure: false) execute during every change-detection cycle, which is necessary for real-time data like timestamps or async streams but incurs a performance penalty.

Creating Custom Pipes for Data Transformation

Building a Pure Pipe

Pure pipes are ideal for deterministic transformations that depend solely on inputs. The following example, adapted from [packages/examples/core/ts/pipes/truncate.ts](https://github.com/angular/angular/blob/main/packages/examples/core/ts/pipes/truncate.ts), demonstrates a string truncation pipe:

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

@Pipe({name: 'truncate'})
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit = 20): string {
    if (!value) return '';
    return value.length > limit ? value.slice(0, limit) + '…' : value;
  }
}

Template usage:

<p>{{ longText | truncate:30 }}</p>

Understanding Impure Pipes

Impure pipes are required when the output depends on external state or must update continuously. The following pipe displays the current time, updating every change-detection cycle:

@Pipe({name: 'now', pure: false})
export class NowPipe implements PipeTransform {
  transform(): Date { 
    return new Date(); 
  }
}
<span>The time is {{ '' | now }}</span>

Use impure pipes sparingly, as they execute on every change-detection cycle regardless of input stability.

Handling Cleanup with OnDestroy

Pipes that allocate resources, such as timers or subscriptions, should implement OnDestroy to prevent memory leaks. The following example from the test suite in [packages/core/test/acceptance/pipe_spec.ts](https://github.com/angular/angular/blob/main/packages/core/test/acceptance/pipe_spec.ts) demonstrates a counting pipe with cleanup logic:

@Pipe({name: 'counter'})
export class CounterPipe implements PipeTransform, OnDestroy {
  private timerId: any;
  private count = 0;

  transform(step = 1): number {
    if (!this.timerId) {
      this.timerId = setInterval(() => this.count += step, 1000);
    }
    return this.count;
  }

  ngOnDestroy() {
    clearInterval(this.timerId);
  }
}
<div>Count: {{ '' | counter:2 }}</div>

Pure vs Impure Pipes Performance Implications

Choosing between pure and impure pipes directly impacts application performance. Pure pipes leverage Angular's change-detection optimizations because the framework caches results and skips re-execution when inputs remain stable. This makes pure pipes suitable for expensive computations like formatting large datasets or complex mathematical operations.

Impure pipes bypass these optimizations. Because they execute during every change-detection cycle, they can trigger cascading updates and degrade performance in large applications. Reserve impure pipes for inherently time-dependent data or when integrating with external streams that Angular cannot observe directly.

Summary

  • The angular pipe function for data transformation relies on the PipeTransform interface defined in packages/core/src/change_detection/pipe_transform.ts, requiring a transform method that accepts a value and optional arguments.
  • Runtime execution occurs in packages/core/src/render3/pipe.ts, where the framework retrieves pipe instances from the LView and guards against null values during invocation.
  • Pipes are pure by default (pure: true), executing only when inputs change, while impure pipes (pure: false) run every change-detection cycle.
  • Implement OnDestroy in pipes that manage timers or subscriptions to prevent memory leaks, as demonstrated in the test suite at packages/core/test/acceptance/pipe_spec.ts.

Frequently Asked Questions

What is the difference between a pure and impure pipe in Angular?

A pure pipe executes only when Angular detects a change in the input value or arguments, enabling performance optimizations through memoization. An impure pipe executes during every change-detection cycle regardless of input stability, which is necessary for real-time data but incurs higher performance costs. The purity is controlled by the pure property in the @Pipe decorator metadata.

How do I pass multiple arguments to an Angular pipe?

You pass multiple arguments to a pipe by separating them with colons in the template expression. The transform method in your pipe class receives the input value as the first parameter, followed by each argument in order. For example, {{ value | myPipe:arg1:arg2 }} invokes transform(value, arg1, arg2).

Can a pipe access other services or dependencies?

Yes, pipes can inject dependencies through their constructors just like components and services. Because pipes are registered in Angular's injector system when decorated with @Pipe, you can request services, HTTP clients, or other providers in the constructor. However, be cautious with impure pipes that inject services, as they may trigger excessive service calls during frequent change-detection cycles.

When should I use a pipe versus a component method?

Use a pipe when the transformation logic is reusable across multiple components, involves pure data formatting, or benefits from Angular's built-in memoization (for pure pipes). Use a component method when the logic requires access to component state, performs side effects, or is specific to a single view. Pipes keep templates declarative and testable, while methods offer flexibility for complex component-specific logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →