Pipes
Built-in Pipes
Section intitulée « Built-in Pipes »@Component({ template: ` <!-- String pipes --> <p>{{ 'hello' | uppercase }}</p> <!-- HELLO --> <p>{{ 'HELLO' | lowercase }}</p> <!-- hello --> <p>{{ 'hello world' | titlecase }}</p> <!-- Hello World -->
<!-- Number pipes --> <p>{{ 1234.56 | number:'1.2-2' }}</p> <!-- 1,234.56 --> <p>{{ 0.259 | percent }}</p> <!-- 26% --> <p>{{ 1234.56 | currency:'USD' }}</p> <!-- $1,234.56 --> <p>{{ 1234.56 | currency:'EUR':'symbol':'1.2-2':'fr' }}</p> <!-- 1 234,56 € -->
<!-- Date pipe --> <p>{{ today | date }}</p> <!-- Jan 1, 2024 --> <p>{{ today | date:'short' }}</p> <!-- 1/1/24, 12:00 PM --> <p>{{ today | date:'fullDate' }}</p> <!-- Monday, January 1, 2024 --> <p>{{ today | date:'yyyy-MM-dd' }}</p> <!-- 2024-01-01 -->
<!-- JSON pipe --> <pre>{{ user | json }}</pre>
<!-- Slice pipe --> <p>{{ [1,2,3,4,5] | slice:1:3 }}</p> <!-- [2,3] -->
<!-- Async pipe --> <p>{{ users$ | async }}</p>
<!-- KeyValue pipe --> <div *ngFor="let item of object | keyvalue"> {{ item.key }}: {{ item.value }} </div> `})export class PipesExampleComponent { today = new Date(); user = { name: 'John', age: 30 }; users$ = this.userService.getUsers(); object = { a: 1, b: 2, c: 3 };}Custom Pipe
Section intitulée « Custom Pipe »import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'truncate', standalone: true})export class TruncatePipe implements PipeTransform { transform(value: string, limit: number = 10, trail: string = '...'): string { if (!value) return ''; return value.length > limit ? value.substring(0, limit) + trail : value; }}
// Usage<p>{{ longText | truncate:20:'...' }}</p>Pure vs Impure Pipes
Section intitulée « Pure vs Impure Pipes »// Pure pipe (default) - s'exécute uniquement lorsque la référence d'entrée change@Pipe({ name: 'filter', standalone: true, pure: true // default})export class FilterPipe implements PipeTransform { transform(items: any[], searchText: string): any[] { if (!items || !searchText) return items; return items.filter(item => item.name.toLowerCase().includes(searchText.toLowerCase()) ); }}
// Impure pipe - runs on every change detection@Pipe({ name: 'impureFilter', standalone: true, pure: false // runs every CD cycle})export class ImpureFilterPipe implements PipeTransform { transform(items: any[], searchText: string): any[] { return items.filter(item => item.name.includes(searchText)); }}Async Pipe
Section intitulée « Async Pipe »@Component({ template: ` <!-- S'abonne et se désabonne automatiquement --> <div *ngIf="users$ | async as users"> <p *ngFor="let user of users">{{ user.name }}</p> </div>
<!-- Multiple subscriptions (bad) --> <div *ngIf="users$ | async"> <p>Count: {{ (users$ | async)?.length }}</p> <!-- Don't do this --> </div>
<!-- Single subscription (good) --> <div *ngIf="users$ | async as users"> <p>Count: {{ users.length }}</p> </div> `})export class UserListComponent { users$ = this.userService.getUsers();}Chaining Pipes
Section intitulée « Chaining Pipes »@Component({ template: ` <!-- Apply multiple pipes --> <p>{{ name | uppercase | slice:0:10 }}</p>
<!-- Date formatting and localization --> <p>{{ date | date:'fullDate' | uppercase }}</p>
<!-- Number formatting --> <p>{{ price | currency:'USD' | uppercase }}</p> `})Common Custom Pipes
Section intitulée « Common Custom Pipes »Filter Pipe
Section intitulée « Filter Pipe »@Pipe({ name: 'filter', standalone: true })export class FilterPipe implements PipeTransform { transform(items: any[], field: string, value: any): any[] { if (!items || !field || value === undefined) return items; return items.filter(item => item[field] === value); }}
// Usage<div *ngFor="let user of users | filter:'active':true"> {{ user.name }}</div>Sort Pipe
Section intitulée « Sort Pipe »@Pipe({ name: 'sort', standalone: true })export class SortPipe implements PipeTransform { transform(items: any[], field: string, reverse: boolean = false): any[] { if (!items || !field) return items;
const sorted = [...items].sort((a, b) => { if (a[field] < b[field]) return -1; if (a[field] > b[field]) return 1; return 0; });
return reverse ? sorted.reverse() : sorted; }}
// Usage<div *ngFor="let user of users | sort:'name':false"> {{ user.name }}</div>Safe HTML Pipe
Section intitulée « Safe HTML Pipe »import { Pipe, PipeTransform } from '@angular/core';import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({ name: 'safeHtml', standalone: true })export class SafeHtmlPipe implements PipeTransform { constructor(private sanitizer: DomSanitizer) {}
transform(html: string): SafeHtml { return this.sanitizer.bypassSecurityTrustHtml(html); }}
// Usage<div [innerHTML]="htmlContent | safeHtml"></div>Time Ago Pipe
Section intitulée « Time Ago Pipe »@Pipe({ name: 'timeAgo', standalone: true })export class TimeAgoPipe implements PipeTransform { transform(value: Date | string): string { const date = new Date(value); const now = new Date(); const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
const intervals = { year: 31536000, month: 2592000, week: 604800, day: 86400, hour: 3600, minute: 60, second: 1 };
for (const [unit, secondsInUnit] of Object.entries(intervals)) { const interval = Math.floor(seconds / secondsInUnit); if (interval >= 1) { return interval === 1 ? `1 ${unit} ago` : `${interval} ${unit}s ago`; } }
return 'just now'; }}
// Usage<p>{{ post.createdAt | timeAgo }}</p> <!-- 2 hours ago -->Pipe with Dependencies
Section intitulée « Pipe with Dependencies »@Pipe({ name: 'translate', standalone: true })export class TranslatePipe implements PipeTransform { constructor(private translateService: TranslateService) {}
transform(key: string, params?: any): string { return this.translateService.instant(key, params); }}
// Usage<p>{{ 'WELCOME_MESSAGE' | translate:{ name: userName } }}</p>Bonnes Pratiques
Section intitulée « Bonnes Pratiques »- Utiliser les pure pipes quand c’est possible (meilleures performances)
- Utiliser le async pipe pour les observables (désabonnement automatique)
- Éviter les impure pipes (ils s’exécutent à chaque détection de changement)
- Ne pas utiliser les pipes pour filtrer/trier de grandes listes (utiliser la logique du composant)
- Garder la logique des pipes simple et rapide
- Utiliser la mémoïsation pour les calculs coûteux
- Préférer plusieurs async pipes plutôt que les abonnements manuels

