Template Syntax
Pipes
Data is often raw and unpolished. Pipes are the make-up of your app. They format data for display without altering the actual logic.
In the database, I store dates as ISO strings (2023-12-24T18:00:00Z) or prices as plain numbers (49.5). However, I never want to show them to the user like this. They expect "Dec 24" and "$49.50".
In the past, I often performed this transformation in TypeScript. This is "dirty". Pipes solve this directly in the HTML. They transform the value only for the view, while the data remains clean and untouched in the background.
1. The Simulation
See the difference between "Raw Data" (left) and "Piped Data" (right). Angular provides powerful built-ins like DatePipe, CurrencyPipe, and JsonPipe out of the box.
2. Custom Pipes
The built-ins cover 90% of cases, but sometimes I need custom logic. A classic example is a Truncate Pipe. If a blog title is too long for the card, it should gracefully end with "...".
Step 1: The Logic (Pipe)
A pipe is just a class with the @Pipe decorator. The heart of it is the transform method.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate', // This is how you use it: {{ val | truncate }}
standalone: true
})
export class TruncatePipe implements PipeTransform {
// The 'transform' method is mandatory.
// value: The data coming in before the pipe (|)
// limit: An optional argument passed with :
transform(value: string, limit: number = 20): string {
if (!value) return '';
if (value.length <= limit) {
return value;
}
// Cut string and append dots
return value.substring(0, limit) + '...';
}
}Step 2: The Usage
Now we can use the pipe anywhere in our templates. We can even pass arguments using the colon : syntax.
<!-- 1. Default limit (20) -->
<p>{{ articleDescription | truncate }}</p>
<!-- 2. Custom limit (passing arguments with :) -->
<p>{{ articleDescription | truncate:50 }}</p>
<!-- 3. Chaining Pipes (Chainable) -->
<!-- First truncate, then uppercase -->
<p>{{ title | truncate:10 | uppercase }}</p>Performance Win: Pipes are "pure" by default. This means Angular executes them ONLY when the input value changes.
If you use a method in HTML (e.g. {{ formatData(val) }}), it runs on EVERY change detection cycle (potentially 100x per second). Always use pipes for formatting!