Maîtrisez les pipes Angular : découvrez les pipes intégrés (date, currency, async) et créez vos propres pipes personnalisés pour transformer vos données.
Qu'est-ce qu'un pipe Angular
Un pipe est une fonction de transformation qui s'utilise directement dans les templates Angular avec l'opérateur |. Il prend une valeur en entrée, l'applique, et retourne une valeur transformée.
<!-- Sans pipe -->
<p>{{ getPrix(product.price) }}</p>
<!-- Avec pipe -->
<p>{{ product.price | currency:'EUR':'symbol':'1.2-2':'fr' }}</p>
Les pipes sont purs par défaut : Angular ne les réexécute que si la valeur d'entrée change (référence), ce qui les rend très performants.
Pipes intégrés essentiels
<!-- DatePipe -->
{{ today | date:'dd/MM/yyyy' }}
{{ today | date:'long':'':'fr' }}
<!-- CurrencyPipe -->
{{ price | currency:'EUR':'symbol':'1.2-2':'fr' }}
<!-- Résultat : 1 234,56 € -->
<!-- DecimalPipe -->
{{ 3.14159 | number:'1.2-3' }}
<!-- Résultat : 3,142 -->
<!-- PercentPipe -->
{{ 0.75 | percent }}
<!-- Résultat : 75% -->
<!-- UpperCase / LowerCase / TitleCase -->
{{ 'hello world' | titlecase }}
<!-- Résultat : Hello World -->
<!-- SlicePipe -->
{{ [1, 2, 3, 4, 5] | slice:1:3 }}
<!-- Résultat : [2, 3] -->
<!-- JsonPipe (debug) -->
<pre>{{ data | json }}</pre>
<!-- KeyValuePipe -->
@for (item of obj | keyvalue; track item.key) {
<p>{{ item.key }}: {{ item.value }}</p>
}
Le pipe async
Le pipe async est particulièrement puissant : il s'abonne automatiquement à un Observable ou une Promise, affiche la valeur émise, et désabonne automatiquement à la destruction du composant.
@Component({
selector: 'app-users',
standalone: true,
imports: [AsyncPipe, NgFor],
template: `
@if (users$ | async; as users) {
@for (user of users; track user.id) {
<div>{{ user.name }}</div>
}
} @else {
<p>Chargement...</p>
}
`
})
export class UsersComponent {
users$ = this.userService.getAll(); // Observable<User[]>
constructor(private userService: UserService) {}
}
async évite les fuites mémoire (memory leaks) car il gère le cycle de vie de la subscription automatiquement. Préférez-le à subscribe() dans le template.
Créer un pipe personnalisé
Générer un pipe avec Angular CLI :
ng generate pipe shared/truncate
Exemple de pipe pour tronquer un texte :
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true,
pure: true // défaut : true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, maxLength: number = 100, suffix: string = '...'): string {
if (!value || value.length <= maxLength) {
return value;
}
return value.substring(0, maxLength).trim() + suffix;
}
}
Utilisation dans un template :
<!-- Import dans le composant -->
@Component({
imports: [TruncatePipe],
template: `
<p>{{ article.description | truncate:150 }}</p>
<p>{{ article.content | truncate:80:'… Lire la suite' }}</p>
`
})
Pipes purs vs impurs
Un pipe pur (défaut) n'est réexécuté que si la référence de la valeur d'entrée change. Un pipe impur s'exécute à chaque cycle de détection de changements.
// Pipe impur : s'exécute à chaque tick (attention aux performances)
@Pipe({
name: 'filterActive',
standalone: true,
pure: false // impur
})
export class FilterActivePipe implements PipeTransform {
transform(items: Item[]): Item[] {
return items.filter(item => item.active);
}
}
// Alternative recommandée : pipe pur avec objet immuable
// Plutôt que de muter le tableau, créer un nouveau tableau
items = [...this.items, newItem]; // Angular détecte le changement
Pipes standalone
Depuis Angular 17, les pipes standalone sont la norme. Un pipe standalone peut être importé directement dans un composant sans passer par un NgModule :
// truncate.pipe.ts
@Pipe({ name: 'truncate', standalone: true })
export class TruncatePipe implements PipeTransform { ... }
// Dans le composant
@Component({
standalone: true,
imports: [TruncatePipe], // importé directement
template: `{{ text | truncate:100 }}`
})
export class ArticleComponent {}
Vous pouvez également créer une librairie de pipes réutilisables en les exportant depuis un barrel :
// shared/pipes/index.ts
export { TruncatePipe } from './truncate.pipe';
export { FormatFileSizePipe } from './format-file-size.pipe';
export { TimeAgoPipe } from './time-ago.pipe';