DEV Community

Cover image for Angular Pipes: A Comprehensive guide
bytebantz
bytebantz

Posted on

Angular Pipes: A Comprehensive guide

Pipes in Angular are simple functions used to transform data in templates without modifying the underlying data. Pipes take in a value, process it, and return a formatted or transformed output. They are often used for formatting dates, numbers, strings, and even arrays or objects.

They allow you to format and display data in a more readable or relevant format directly in the view without altering the underlying data model.

Using pipes helps in keeping the code clean and readable. Instead of writing complex logic in the templates or components, you can encapsulate that logic in a pipe, which can then be reused across different parts of your application.
For example, if you’re developing a blog platform where users can see the publication date of articles. Dates need to be displayed in a user-friendly format, such as “August 31, 2024,” instead of the raw format “2024–08–31T14:48:00.000Z”. With pipes, you can use Angular’s built-in DatePipe in the template instead of manually formatting the date in the component, cluttering the code and reducing readability.

<p>Published on: {{ article.publishDate | date:'longDate' }}</p>
Enter fullscreen mode Exit fullscreen mode

To apply a pipe, use the pipe operator (|) within a template expression as shown in the above code example.

Built-in Pipes

Angular comes with several built-in pipes that cover common tasks (DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe, AsyncPipe, JsonPipe, etc.). Knowing how to use these can make your code cleaner and more efficient.

Examples:

<pre>{{ user | json }}</pre>
<p>Price: {{ product.price | currency:'USD' }}</p>
<p>{{ user.name | uppercase }}</p>
Enter fullscreen mode Exit fullscreen mode

Parametrized Pipes

Many Angular pipes accept parameters to customize their behavior.

To specify the parameter, follow the pipe name with a colon (:) and the parameter value

Some pipes accept multiple parameters, which are separated by additional colons.

Parameters can be optional or required. Suppose you have a custom pipe that formats currency and requires you to specify the currency type as a parameter. If this parameter is not provided, the pipe might not be able to format the value correctly.

<p>The product price is {{ price | customCurrency:'USD' }}</p>
Enter fullscreen mode Exit fullscreen mode

1. DatePipe with Parameters

<p>Published on: {{ article.publishDate | date:'MMMM d, y, h:mm:ss a' }}</p>
Enter fullscreen mode Exit fullscreen mode

This formats the date as “August 31, 2024, 2:48:00 PM”.

2. CurrencyPipe with Parameters

<p>Price: {{ product.price | currency:'EUR':'symbol-narrow':'1.0-0' }}</p>
Enter fullscreen mode Exit fullscreen mode

This formats the price as “€1,235” (rounded to no decimal places).

Chaining Pipes

You can chain multiple pipes together to achieve complex transformations.

<p>{{ article.content | slice:0:100 | uppercase }}</p>
Enter fullscreen mode Exit fullscreen mode

This will slice the first 100 characters of article.content and convert them to uppercase.

Custom Pipes

Sometimes, the built-in pipes may not meet your specific needs and you will need to create a custom pipe to handle the specific logic. Here’s how you can do it.

Example:

In the following example we are going to create a pipe that adds a greeting to a name like “Hello, Alice!”

Run the following command to generate a new pipe:

ng generate pipe greet
Enter fullscreen mode Exit fullscreen mode

Now, let’s modify the greet.pipe.ts file in the src/app directory to include the pipe logic:

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

@Pipe({
  name: 'greet',  // This is the name you'll use in the template
  standalone: true,
})
export class GreetPipe implements PipeTransform {
  transform(value: string): string {
    return `Hello, ${value}!`;  // This is the transformation logic
  }
}
Enter fullscreen mode Exit fullscreen mode

Once your pipe is ready, you can use it in your templates.

<p>{{ 'Alice' | greet }}</p>
Enter fullscreen mode Exit fullscreen mode

Creating a Parameterized Custom Pipe

Now we are going to make the greeting customizable, so you can say “Hi, Alice!” or “Welcome, Alice!” depending on what you pass to the pipe.

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

@Pipe({
  name: 'greet',  // Same pipe name as before
  standalone: true,
})
export class GreetPipe implements PipeTransform {
  transform(value: string, greeting: string = 'Hello'): string {
    return `${greeting}, ${value}!`;  // Now it uses the greeting passed in
  }
}
Enter fullscreen mode Exit fullscreen mode

The transform method now has a second parameter, greeting. If no greeting is provided, it defaults to “Hello”.

Now you can customize the greeting in your templates.

<p>{{ 'Alice' | greet:'Hi' }}</p>
<p>{{ 'Bob' | greet:'Welcome' }}</p>
Enter fullscreen mode Exit fullscreen mode

Pure vs. Impure Pipes

1. Pure Pipes
By default, all Angular pipes are pure. A pure pipe only gets called when input data (like a number or a string) or when the reference to an object (like an array or date) changes. This makes pure pipes efficient and performant because the pipe doesn’t run unnecessarily.

However, if your data is more complex, like an array of items, Angular might not notice changes inside the array (like adding a new item) because the reference to the array hasn’t changed.

Unless necessary, keep your pipes pure to avoid unnecessary re-renders and to maintain performance.

Example:

@Pipe({
  name: "onSale",
  standalone: true,
  pure: true,
})
export class OnSalePipe implements PipeTransform {
  transform(items: Item[]): Item[] {
    return items.filter((item) => item.isOnSale);
  }
}
Enter fullscreen mode Exit fullscreen mode

In your template:

<ul>
  <li *ngFor="let item of (items | onSale)">
    {{ item.name }} - {{ item.price | formatPrice }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

If you add a new item to the items array that’s on sale, you might expect it to show up in the list. But if you simply push the new item into the array, the list might not update because the array reference hasn’t changed.

2. Impure Pipes

An impure pipe, on the other hand, is called every time Angular performs a change detection cycle. However, because they run so often, they can slow down your app.

Example:

@Pipe({
  name: "onSaleImpure",
  standalone: true,
  pure: false,
})
export class OnSaleImpurePipe implements PipeTransform {
  transform(items: Item[]): Item[] {
    return items.filter((item) => item.isOnSale);
  }
}
Enter fullscreen mode Exit fullscreen mode

In your template:

<ul>
  <li *ngFor="let item of (items | onSaleImpure)">
    {{ item.name }} - {{ item.price | formatPrice }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Now, when you add a new item, the pipe will notice the change and update the list.

Best Practices for Using Pipes

  1. Keep Pipes Simple. Avoid Heavy Computations in Pipes

  2. Name Pipes Clearly and Descriptively

  3. Keep Pipes Focused on a Single Responsibility

  4. Avoid Impure Pipes When Possible

  5. Test Custom Pipes Thoroughly

Conclusion

Angular pipes streamline data transformation tasks, making your code more modular, reusable, and maintainable. They help to enforce consistency across the application and improve the readability of your templates, which is crucial for developing scalable and maintainable applications.

Top comments (0)