Skip to main content

Angular Pipes

Introduction

Angular pipes are a powerful feature that allows you to transform data directly in your templates. Think of pipes as simple functions that take an input value, process it, and return a transformed output to display to the user. They help keep your component logic clean by handling data formatting concerns in the template.

Pipes are particularly useful for tasks like:

  • Formatting dates
  • Converting text to uppercase or lowercase
  • Displaying numbers with specific decimal places
  • Converting objects to JSON strings for debugging
  • Filtering or sorting arrays

In this tutorial, we'll explore how to use Angular's built-in pipes, chain multiple pipes together, and create custom pipes for specialized formatting needs.

Angular's Built-in Pipes

Angular comes with several built-in pipes that handle common data transformation tasks. Let's look at some of the most frequently used ones:

DatePipe

The DatePipe formats dates according to locale rules.

typescript
// In your component
currentDate = new Date();
html
<!-- In your template -->
<p>Today's date: {{ currentDate | date }}</p>
<p>Custom format: {{ currentDate | date:'MM/dd/yyyy' }}</p>
<p>Full date: {{ currentDate | date:'fullDate' }}</p>
<p>Short time: {{ currentDate | date:'shortTime' }}</p>

Output:

Today's date: Jun 15, 2023
Custom format: 06/15/2023
Full date: Thursday, June 15, 2023
Short time: 10:30 AM

UpperCasePipe and LowerCasePipe

These pipes transform text to all uppercase or all lowercase letters.

typescript
// In your component
title = 'Angular Pipes Tutorial';
html
<!-- In your template -->
<p>Original: {{ title }}</p>
<p>Uppercase: {{ title | uppercase }}</p>
<p>Lowercase: {{ title | lowercase }}</p>

Output:

Original: Angular Pipes Tutorial
Uppercase: ANGULAR PIPES TUTORIAL
Lowercase: angular pipes tutorial

DecimalPipe

The DecimalPipe formats numbers with decimal points.

typescript
// In your component
price = 42.5;
html
<!-- In your template -->
<p>Default: {{ price | number }}</p>
<p>With 2 decimal places: {{ price | number:'1.2-2' }}</p>
<p>With 3 decimal places: {{ price | number:'1.3-3' }}</p>

Output:

Default: 42.5
With 2 decimal places: 42.50
With 3 decimal places: 42.500

The format pattern '1.2-2' means: at least 1 digit before decimal point, exactly 2 digits after decimal point.

CurrencyPipe

The CurrencyPipe formats numbers as currency values.

typescript
// In your component
productPrice = 49.99;
html
<!-- In your template -->
<p>USD: {{ productPrice | currency }}</p>
<p>EUR: {{ productPrice | currency:'EUR' }}</p>
<p>GBP with custom format: {{ productPrice | currency:'GBP':'symbol':'1.2-2' }}</p>

Output:

USD: $49.99
EUR: €49.99
GBP with custom format: £49.99

PercentPipe

The PercentPipe formats numbers as percentages.

typescript
// In your component
progressValue = 0.76;
html
<!-- In your template -->
<p>Progress: {{ progressValue | percent }}</p>
<p>Progress (1 decimal): {{ progressValue | percent:'1.1-1' }}</p>

Output:

Progress: 76%
Progress (1 decimal): 76.0%

SlicePipe

The SlicePipe creates a subset of an array or string.

typescript
// In your component
message = 'Learn Angular Step by Step';
items = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'];
html
<!-- In your template -->
<p>Sliced string: {{ message | slice:0:5 }}</p>
<p>Sliced string 2: {{ message | slice:6:13 }}</p>

<p>Original array: {{ items }}</p>
<p>First two items: {{ items | slice:0:2 }}</p>
<p>Last two items: {{ items | slice:-2 }}</p>

Output:

Sliced string: Learn
Sliced string 2: Angular
Original array: Item 1,Item 2,Item 3,Item 4,Item 5
First two items: Item 1,Item 2
Last two items: Item 4,Item 5

JsonPipe

The JsonPipe converts objects to JSON strings, which is useful for debugging.

typescript
// In your component
userObject = {
name: 'John',
age: 28,
address: {
city: 'New York',
country: 'USA'
}
};
html
<!-- In your template -->
<pre>{{ userObject | json }}</pre>

Output:

json
{
"name": "John",
"age": 28,
"address": {
"city": "New York",
"country": "USA"
}
}

Chaining Pipes

One of the powerful features of Angular pipes is the ability to chain them together. The output of one pipe becomes the input for the next pipe.

typescript
// In your component
currentDate = new Date();
html
<!-- In your template -->
<p>Date with chained pipes: {{ currentDate | date:'fullDate' | uppercase }}</p>
<p>Price with chained pipes: {{ productPrice | currency:'USD':'symbol' | slice:0:1 }}</p>

Output:

Date with chained pipes: THURSDAY, JUNE 15, 2023
Price with chained pipes: $

Pipe Parameters

Many pipes accept parameters to customize their behavior. Parameters are passed to pipes using colons.

html
<!-- Basic syntax -->
{{ value | pipeName:parameter1:parameter2 }}

For example, the date pipe accepts a format parameter:

html
<!-- Format date as MM/dd/yyyy -->
{{ currentDate | date:'MM/dd/yyyy' }}

Creating Custom Pipes

While Angular provides many useful built-in pipes, you may need to create custom pipes for specific requirements. Let's create a custom pipe that truncates text and adds an ellipsis if it exceeds a certain length.

Step 1: Generate a new pipe using Angular CLI

bash
ng generate pipe truncate

This command creates a truncate.pipe.ts file with boilerplate code.

Step 2: Implement the pipe logic

typescript
// truncate.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'truncate'
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number = 20, completeWords: boolean = false, ellipsis: string = '...'): string {
if (!value) {
return '';
}

if (value.length <= limit) {
return value;
}

if (completeWords) {
limit = value.substring(0, limit).lastIndexOf(' ');
}

return value.substring(0, limit) + ellipsis;
}
}

Step 3: Use the custom pipe in your template

typescript
// In your component
longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam in dui mauris.';
html
<!-- In your template -->
<p>Original: {{ longText }}</p>
<p>Truncated (default): {{ longText | truncate }}</p>
<p>Truncated (10 chars): {{ longText | truncate:10 }}</p>
<p>Truncated (30 chars, complete words): {{ longText | truncate:30:true }}</p>
<p>Truncated (custom ellipsis): {{ longText | truncate:15:false:' [read more]' }}</p>

Output:

Original: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam in dui mauris.
Truncated (default): Lorem ipsum dolor si...
Truncated (10 chars): Lorem ipsu...
Truncated (30 chars, complete words): Lorem ipsum dolor sit amet...
Truncated (custom ellipsis): Lorem ipsum do [read more]

Pure and Impure Pipes

Angular pipes come in two varieties: pure and impure.

  • Pure pipes (default) are executed only when Angular detects a pure change to the input value. A pure change is either a change to a primitive input value (String, Number, Boolean, Symbol) or a changed object reference (Date, Array, Function, Object).

  • Impure pipes are executed during every component change detection cycle, which means much more frequently. This is useful when the pipe needs to handle inputs that change in ways that cannot be detected by Angular's change detection, such as when a property of an object changes.

Here's how to create an impure pipe:

typescript
@Pipe({
name: 'filterItems',
pure: false // This makes the pipe impure
})
export class FilterItemsPipe implements PipeTransform {
transform(items: any[], filter: string): any[] {
if (!items || !filter) {
return items;
}

return items.filter(item => item.title.toLowerCase().includes(filter.toLowerCase()));
}
}

Note: Use impure pipes cautiously as they can impact performance.

Real-world Example: Building a Filter Pipe

Let's create a practical example of a filter pipe for a product list:

Step 1: Generate the pipe

bash
ng generate pipe filter

Step 2: Implement the filter pipe

typescript
// filter.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'filter',
pure: false // Impure pipe to detect all changes
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string, propertyName: string): any[] {
if (!items || !searchText || !propertyName) {
return items;
}

searchText = searchText.toLowerCase();

return items.filter(item => {
const value = item[propertyName].toLowerCase();
return value.includes(searchText);
});
}
}

Step 3: Use the filter pipe in a product search component

typescript
// product-list.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html'
})
export class ProductListComponent {
searchTerm = '';

products = [
{ id: 1, name: 'Laptop', category: 'Electronics', price: 999.99 },
{ id: 2, name: 'Smartphone', category: 'Electronics', price: 699.99 },
{ id: 3, name: 'Headphones', category: 'Accessories', price: 199.99 },
{ id: 4, name: 'Mouse', category: 'Accessories', price: 29.99 },
{ id: 5, name: 'Keyboard', category: 'Computing', price: 59.99 }
];
}
html
<!-- product-list.component.html -->
<div>
<h2>Product Search</h2>

<input
type="text"
placeholder="Search products..."
[(ngModel)]="searchTerm"
/>

<table>
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let product of products | filter:searchTerm:'name'">
<td>{{ product.name }}</td>
<td>{{ product.category }}</td>
<td>{{ product.price | currency }}</td>
</tr>
</tbody>
</table>

<p *ngIf="(products | filter:searchTerm:'name').length === 0">
No products found matching "{{ searchTerm }}"
</p>
</div>

This example creates a simple product search that filters the product list as the user types. It demonstrates how pipes can simplify template logic while keeping the component code clean.

Best Practices for Using Pipes

  1. Prefer pure pipes whenever possible for better performance.
  2. Avoid complex operations in pipes, especially impure ones.
  3. Use standalone functions for non-UI data transformations instead of pipes.
  4. Consider caching results for expensive pipe operations.
  5. Test your pipes thoroughly, especially when dealing with edge cases.
  6. Keep pipes focused on a single responsibility.
  7. Provide meaningful defaults for optional pipe parameters.

Summary

Angular pipes are powerful tools that help you transform and format data directly in your templates. We've covered:

  • Built-in pipes like DatePipe, UpperCasePipe, DecimalPipe, and more
  • Chaining pipes to perform multiple transformations in sequence
  • Creating custom pipes to handle specific formatting requirements
  • Pure vs. impure pipes and when to use each
  • Practical examples of pipes in real-world applications

Pipes help keep your components cleaner by handling data transformation logic in the templates, leading to more maintainable and readable code.

Additional Resources

Exercises

  1. Create a custom pipe that formats phone numbers from 1234567890 to (123) 456-7890.
  2. Build a search feature that uses your own custom filter pipe to filter a list of items.
  3. Create a sort pipe that can sort an array of objects by a specified property.
  4. Modify the truncate pipe we built to handle HTML content safely.
  5. Create a timeAgo pipe that displays dates in a relative format (e.g., "5 minutes ago", "2 days ago").

By mastering Angular pipes, you'll be able to handle data presentation effectively and keep your component logic focused on business rules rather than formatting concerns.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)