In Angular, pipes are a powerful feature used to transform data in templates before displaying it to the user. They allow developers to format and transform values directly within the HTML, without changing the underlying data. Angular provides several built-in pipes for common transformations, and you can also create custom pipes to handle more specific use cases.
1. What is a Pipe?
A pipe in Angular is a function that takes in a value, processes it, and returns a transformed value. Pipes are typically used in Angular templates to format data, such as numbers, dates, or strings, in a user-friendly way.
For example, to format a date:
<p>{{ today | date }}</p>
Here, date is a pipe that transforms the current date into a readable format.
2. Using Built-In Pipes
Angular comes with a variety of built-in pipes to handle common data transformations. Here are some of the most commonly used ones:
a) DatePipe (date)
- Formats a date value according to locale rules.
<p>{{ today | date }}</p> <!-- Outputs: Sep 18, 2024 -->
<p>{{ today | date: 'fullDate' }}</p> <!-- Outputs: Wednesday, September 18, 2024 -->
<p>{{ today | date: 'shortTime' }}</p> <!-- Outputs: 8:30 AM -->
b) UpperCasePipe (uppercase)
- Transforms text to uppercase.
<p>{{ 'hello world' | uppercase }}</p> <!-- Outputs: HELLO WORLD -->
c) LowerCasePipe (lowercase)
- Transforms text to lowercase.
<p>{{ 'HELLO WORLD' | lowercase }}</p> <!-- Outputs: hello world -->
d) CurrencyPipe (currency)
- Formats a number as a currency string.
<p>{{ 1234.56 | currency }}</p> <!-- Outputs: $1,234.56 (default currency: USD) -->
<p>{{ 1234.56 | currency: 'EUR' }}</p> <!-- Outputs: €1,234.56 -->
e) DecimalPipe (number)
- Formats a number to a specified decimal format.
<p>{{ 1234.56 | number: '1.2-2' }}</p> <!-- Outputs: 1,234.56 -->
<p>{{ 1234.56 | number: '1.0-0' }}</p> <!-- Outputs: 1,235 -->
f) PercentPipe (percent)
- Transforms a number into a percentage format.
<p>{{ 0.25 | percent }}</p> <!-- Outputs: 25% -->
g) JsonPipe (json)
- Converts an object into a JSON string for display.
<p>{{ myObject | json }}</p>
h) SlicePipe (slice)
- Extracts a portion of an array or string.
<p>{{ 'Angular Pipes' | slice:0:7 }}</p> <!-- Outputs: Angular -->
<p>{{ [1, 2, 3, 4, 5] | slice:1:3 }}</p> <!-- Outputs: [2, 3] -->
i) AsyncPipe (async)
- Unwraps asynchronous values (e.g., Promises or Observables) in the template.
<p>{{ asyncData | async }}</p>
3. Chaining Pipes
You can chain multiple pipes together to perform complex transformations. For example, you can use the uppercase pipe in conjunction with the slice pipe to extract and capitalize part of a string:
<p>{{ 'angular pipes' | slice:0:7 | uppercase }}</p> <!-- Outputs: ANGULAR -->
4. Custom Pipes
In addition to the built-in pipes, Angular allows you to create your own custom pipes to handle specific transformations that are not covered by the default pipes.
a) Creating a Custom Pipe
To create a custom pipe, you need to:
- Create a new TypeScript class and implement the
PipeTransforminterface. - Use the
@Pipedecorator to provide metadata about the pipe (such as its name). - Implement the
transform()method to define the pipe’s transformation logic.
Example: A custom pipe to reverse a string
- Generate the Pipe: You can use the Angular CLI to generate a pipe:
ng generate pipe reverse
This will create a reverse.pipe.ts file.
- Define the Pipe:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'reverse'
})
export class ReversePipe implements PipeTransform {
transform(value: string): string {
if (!value) return '';
return value.split('').reverse().join('');
}
}
In this example, the reverse pipe takes a string, splits it into characters, reverses them, and joins them back together.
- Using the Custom Pipe:
Once the custom pipe is created, you can use it in the template just like any other pipe.
<p>{{ 'hello' | reverse }}</p> <!-- Outputs: olleh -->
b) Custom Pipe with Arguments
You can also pass arguments to your custom pipe just like with built-in pipes. Here’s an example of a custom pipe that capitalizes the first letter of each word, with an option to capitalize all letters:
- Custom Pipe Definition:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'capitalize'
})
export class CapitalizePipe implements PipeTransform {
transform(value: string, allWords: boolean = false): string {
if (!value) return '';
if (allWords) {
return value.split(' ').map(word => this.capitalizeWord(word)).join(' ');
} else {
return this.capitalizeWord(value);
}
}
capitalizeWord(word: string): string {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}
}
- Using the Pipe with Arguments:
<p>{{ 'angular pipes' | capitalize }}</p> <!-- Outputs: Angular pipes -->
<p>{{ 'angular pipes' | capitalize:true }}</p> <!-- Outputs: Angular Pipes -->
5. Pure vs. Impure Pipes
Pipes in Angular can be pure or impure, and this distinction affects their performance and usage.
a) Pure Pipes
- Pure pipes are pipes that rely on pure functions, meaning they don’t modify their inputs and always produce the same output for the same input.
- Angular only calls a pure pipe when it detects a change in the input (e.g., a new reference for an object or array).
- By default, all pipes are pure, which makes them efficient.
@Pipe({
name: 'myPurePipe',
pure: true
})
export class MyPurePipe implements PipeTransform {
transform(value: any): any {
// transformation logic here
}
}
b) Impure Pipes
- Impure pipes are called during every change detection cycle, regardless of whether their inputs have changed.
- These are used when the pipe’s output depends on dynamic data (e.g., pipes that work with mutable objects, arrays, or real-time data).
- You can mark a pipe as impure by setting
pure: falsein the@Pipedecorator, but this can impact performance due to the increased number of calls.
@Pipe({
name: 'myImpurePipe',
pure: false
})
export class MyImpurePipe implements PipeTransform {
transform(value: any): any {
// transformation logic here
}
}
Example of Impure Pipe:
@Pipe({
name: 'filter',
pure: false
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchTerm: string): any[] {
if (!items || !searchTerm) {
return items;
}
return items.filter(item => item.name.includes(searchTerm));
}
}
In this example, the filter pipe will be recalculated on every change detection cycle, which can be useful when working with mutable data like arrays.
6. Best Practices for Pipes
- Use Pipes for Presentation Logic: Pipes should only be used for pure data transformation. Avoid putting complex business logic in pipes.
- Prefer Pure Pipes: Unless absolutely necessary, prefer using pure pipes as they are more efficient and only run when inputs change.
- Don’t Use Pipes for Heavy Computations: Avoid using pipes for heavy computations that might affect performance, especially in large applications. If you need to, consider caching the results or using a service instead.
- Modularize Pipes: Consider creating a shared module for custom pipes so they can be easily reused across different parts of the application.
Conclusion
Pipes in Angular are a great way to transform data for presentation without modifying the underlying data in the component. Angular’s built-in pipes handle common transformations like date formatting, currency, and case conversion. For more specialized use cases, developers can create custom pipes, which provide flexibility in transforming
data to fit specific requirements.
