Episode 22 of 27

Custom Filter Pipe

Create your own custom pipe — build a filter pipe that searches and filters list items in real time.

Custom Filter Pipe

Angular's built-in pipes are great, but you can create custom pipes for your specific data transformation needs. Let's build a filter pipe that searches through a list.

Generate a Pipe with the CLI

ng generate pipe filter
# or
ng g p filter

The Generated Pipe

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

@Pipe({
    name: 'filter'
})
export class FilterPipe implements PipeTransform {
    transform(value: unknown, ...args: unknown[]): unknown {
        return null;
    }
}

Building the Filter Pipe

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

@Pipe({
    name: 'filter'
})
export class FilterPipe implements PipeTransform {
    transform(items: any[], searchTerm: string, property: string): any[] {
        // Return all items if no search term
        if (!items || !searchTerm) {
            return items;
        }

        // Filter items where the property contains the search term
        const lowerSearch = searchTerm.toLowerCase();
        return items.filter(item => {
            return item[property].toLowerCase().includes(lowerSearch);
        });
    }
}

Using the Filter Pipe

// component
export class UserListComponent {
    searchTerm = '';
    users = [
        { name: 'Alice Johnson', role: 'Admin' },
        { name: 'Bob Smith', role: 'Developer' },
        { name: 'Carol Williams', role: 'Designer' },
        { name: 'David Brown', role: 'Developer' },
        { name: 'Eve Davis', role: 'Manager' },
    ];
}

// template
<input [(ngModel)]="searchTerm" placeholder="Search users...">

<div *ngFor="let user of users | filter:searchTerm:'name'">
    <h3>{{ user.name }}</h3>
    <p>{{ user.role }}</p>
</div>

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

Multi-Property Search

@Pipe({ name: 'search' })
export class SearchPipe implements PipeTransform {
    transform(items: any[], searchTerm: string, properties: string[]): any[] {
        if (!items || !searchTerm) return items;

        const lower = searchTerm.toLowerCase();
        return items.filter(item => {
            return properties.some(prop =>
                item[prop]?.toString().toLowerCase().includes(lower)
            );
        });
    }
}

// template — search across name AND role:
<div *ngFor="let user of users | search:searchTerm:['name','role']">
    {{ user.name }} — {{ user.role }}
</div>

Custom Formatting Pipe

@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {
    transform(value: string, limit: number = 50, trail: string = '...'): string {
        if (!value) return '';
        if (value.length <= limit) return value;
        return value.substring(0, limit) + trail;
    }
}

// template
<p>{{ longText | truncate:100 }}</p>
<p>{{ description | truncate:50:'…' }}</p>

Registering the Pipe

// app.module.ts
@NgModule({
    declarations: [
        AppComponent,
        FilterPipe,     // Register here
        TruncatePipe,
    ],
    // ...
})

The CLI does this automatically when using ng g p.

Pure vs Impure Pipes

TypeWhen It RunsPerformance
Pure (default)Only when input value changesFast — cached
ImpureOn every change detection cycleSlower — runs constantly
@Pipe({ 
    name: 'filter',
    pure: false  // Makes it impure — runs on every change detection
})

Key Takeaways

  • Create custom pipes with ng g p pipe-name
  • Implement the PipeTransform interface with a transform() method
  • Use pipes in templates: {{ data | pipeName:arg1:arg2 }}
  • Pipes are pure by default — they only re-run when inputs change
  • Custom pipes are perfect for filtering, formatting, and transforming data