Skip to main content
Practice Problems

Pipes in Angular (built-in and custom)

What are Pipes?

Pipes transform data in Angular templates. They take a value, process it, and return a formatted output. Angular provides many built-in pipes and allows you to create custom ones.


Built-in Pipes

html
<!-- DatePipe --> <p>{{ today | date }}</p> <!-- Jan 15, 2026 --> <p>{{ today | date:'fullDate' }}</p> <!-- Thursday, January 15, 2026 --> <p>{{ today | date:'dd/MM/yyyy' }}</p> <!-- 15/01/2026 --> <!-- CurrencyPipe --> <p>{{ price | currency }}</p> <!-- $1,234.50 --> <p>{{ price | currency:'EUR' }}</p> <!-- €1,234.50 --> <p>{{ price | currency:'UAH':'symbol' }}</p> <!-- ₴1,234.50 --> <!-- DecimalPipe --> <p>{{ 3.14159 | number:'1.2-3' }}</p> <!-- 3.142 --> <!-- UpperCase / LowerCase / TitleCase --> <p>{{ 'hello world' | uppercase }}</p> <!-- HELLO WORLD --> <p>{{ 'HELLO' | lowercase }}</p> <!-- hello --> <p>{{ 'hello world' | titlecase }}</p> <!-- Hello World --> <!-- JsonPipe (debugging) --> <pre>{{ user | json }}</pre> <!-- SlicePipe --> <p>{{ 'Angular' | slice:0:3 }}</p> <!-- Ang --> <!-- AsyncPipe --> <p>{{ user$ | async }}</p> <!-- Subscribes automatically -->

The AsyncPipe

The most important pipe — automatically subscribes and unsubscribes from Observables:

typescript
@Component({ template: \` <div *ngIf="user$ | async as user"> <h1>{{ user.name }}</h1> <p>{{ user.email }}</p> </div> \` }) export class UserComponent { user$ = this.userService.getUser(1); constructor(private userService: UserService) {} }

Benefits:

  • No manual subscribe/unsubscribe — prevents memory leaks
  • Automatically triggers change detection
  • Works with Observables and Promises

Creating Custom Pipes

typescript
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'truncate', standalone: true }) 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; } }
html
<p>{{ longText | truncate }}</p> <!-- 50 chars... --> <p>{{ longText | truncate:20 }}</p> <!-- 20 chars... --> <p>{{ longText | truncate:30:'→' }}</p> <!-- 30 chars→ -->

Filter Pipe

typescript
@Pipe({ name: 'filter', standalone: true }) export class FilterPipe implements PipeTransform { transform<T>(items: T[], field: keyof T, value: string): T[] { if (!items || !value) return items; return items.filter(item => String(item[field]).toLowerCase().includes(value.toLowerCase()) ); } }
html
<input [(ngModel)]="searchTerm"> <div *ngFor="let user of users | filter:'name':searchTerm"> {{ user.name }} </div>

Pure vs Impure Pipes

FeaturePure (default)Impure
Re-executes whenInput value reference changesEvery change detection cycle
Performance✅ Efficient❌ Can be slow
Declaration@Pipe({ pure: true }) (default)@Pipe({ pure: false })
Use caseStateless transformsStateful, async, or array mutations

Chaining Pipes

html
<p>{{ birthday | date:'fullDate' | uppercase }}</p> <!-- THURSDAY, JANUARY 15, 2026 -->

Important:

Pipes transform template data without modifying the source. The AsyncPipe is essential — it handles Observable subscriptions automatically and prevents memory leaks. Create custom pipes for reusable formatting logic. Pipes are pure by default (only re-execute on reference change), which is efficient.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems