Angular pipes are a convenient way to transform data in templates. While Angular provides several built-in pipes (e.g., DatePipe
, CurrencyPipe
, JsonPipe
), you can create custom pipes to handle specific transformations tailored to your application’s needs.
This article provides a detailed guide to creating and using custom pipes in Angular, complete with examples, use cases, and best practices.
What are Pipes in Angular?
A pipe is a class decorated with @Pipe
that takes in data as input and transforms it into a desired format. Pipes are typically used in templates with the pipe operator (|
).
Common Built-in Pipes
DatePipe
: Formats dates.UpperCasePipe
: Converts text to uppercase.CurrencyPipe
: Formats numbers as currency.
Example of a Built-in Pipe:
htmlCopy code<p>{{ today | date:'fullDate' }}</p>
When to Use Custom Pipes
Custom pipes are useful when you need to:
- Perform a specific transformation repeatedly.
- Simplify complex logic in templates.
- Format data dynamically based on application-specific requirements.
Examples of Custom Pipes
- Capitalize: Converts the first letter of each word to uppercase.
- Filter: Filters an array based on specific criteria.
- Custom Date Format: Formats dates differently than Angular’s built-in
DatePipe
.
Step-by-Step Implementation of a Custom Pipe
Let’s create a custom pipe to capitalize the first letter of each word in a string.
Step 1: Generate a Pipe
Use the Angular CLI to generate a new pipe:
bashCopy codeng generate pipe capitalize
This creates two files:
capitalize.pipe.ts
: Contains the pipe logic.capitalize.pipe.spec.ts
: Contains unit tests for the pipe.
Step 2: Define the Pipe Logic
Open capitalize.pipe.ts
and implement the transformation logic.
typescriptCopy codeimport { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'capitalize',
})
export class CapitalizePipe implements PipeTransform {
transform(value: string): string {
if (!value) {
return '';
}
return value
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ');
}
}
Explanation
- The
@Pipe
decorator defines the name of the pipe (capitalize
). - The
PipeTransform
interface ensures the class implements thetransform
method. - The
transform
method receives the input value and returns the transformed value.
Step 3: Add the Pipe to a Module
To use the pipe in your application, add it to a module’s declarations
array.
In app.module.ts
:
typescriptCopy codeimport { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { CapitalizePipe } from './capitalize.pipe';
@NgModule({
declarations: [
AppComponent,
CapitalizePipe, // Add the custom pipe here
],
imports: [BrowserModule],
bootstrap: [AppComponent],
})
export class AppModule {}
Step 4: Use the Pipe in a Template
You can now use the capitalize
pipe in your templates.
In app.component.html
:
htmlCopy code<p>{{ 'hello angular world' | capitalize }}</p>
Output:
Copy codeHello Angular World
Step 5: Add Parameters to the Pipe (Optional)
To make the pipe more flexible, you can add parameters. Let’s modify the capitalize
pipe to allow capitalization of:
- Only the first word.
- All words (default behavior).
Updated Pipe:
typescriptCopy codeimport { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'capitalize',
})
export class CapitalizePipe implements PipeTransform {
transform(value: string, mode: 'first' | 'all' = 'all'): string {
if (!value) {
return '';
}
if (mode === 'first') {
return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
}
return value
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ');
}
}
Template Usage:
htmlCopy code<p>{{ 'hello angular world' | capitalize:'first' }}</p>
<p>{{ 'hello angular world' | capitalize:'all' }}</p>
Output:
Copy codeHello angular world
Hello Angular World
Advanced Use Case: Filtering an Array
Let’s create a custom pipe to filter an array of objects based on a search term.
Generate a Pipe:
bashCopy codeng generate pipe filter
Define the Pipe Logic:
typescriptCopy codeimport { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter',
pure: false, // Set to false for dynamic filtering
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchTerm: string, property: string): any[] {
if (!items || !searchTerm) {
return items;
}
return items.filter(item =>
item[property].toLowerCase().includes(searchTerm.toLowerCase())
);
}
}
Template Usage:
htmlCopy code<ul>
<li *ngFor="let item of items | filter:searchTerm:'name'">
{{ item.name }}
</li>
</ul>
<input [(ngModel)]="searchTerm" placeholder="Search by name">
Component:
typescriptCopy codeimport { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = [
{ name: 'John' },
{ name: 'Jane' },
{ name: 'Doe' },
];
searchTerm: string = '';
}
Best Practices for Custom Pipes
- Keep Pipes Pure When Possible
- Pure pipes are more efficient as they only re-evaluate when the input changes.
- Use
pure: false
only when necessary (e.g., for filtering).
- Limit Complexity
- Avoid putting heavy logic in pipes. Instead, use services or methods for complex transformations.
- Reuse Logic
- For reusable transformations, consider using shared modules to define your custom pipes.
- Handle Edge Cases
- Account for
null
,undefined
, and empty values in your pipes.
- Account for
Common Pitfalls
- Overusing Pipes in Templates
- Avoid chaining complex pipes in templates as it can degrade performance.
- Not Handling Null or Undefined Values
- Always check for invalid input in the
transform
method.
- Always check for invalid input in the
- Using Impure Pipes Without Necessity
- Impure pipes are evaluated frequently and can negatively impact performance.
Conclusion
Custom pipes in Angular provide a clean and reusable way to transform data in your templates. By following the step-by-step guide and adhering to best practices, you can create efficient and maintainable custom pipes tailored to your application’s requirements. Whether you’re capitalizing text, filtering arrays, or formatting data, custom pipes are a powerful addition to your Angular toolkit.