Pipes transform data in templates - like a master craftsman polishing a sword blade.
1@Pipe({
2 name: 'truncate',
3 standalone: true
4})
5export class TruncatePipe implements PipeTransform {
6 transform(value: string, limit = 50, trail = '...'): string {
7 if (!value) return '';
8 if (value.length <= limit) return value;
9 return value.substring(0, limit) + trail;
10 }
11}
12
13// Usage
14<p>{{ longText | truncate }}</p>
15<p>{{ longText | truncate:100:'...' }}</p>1@Pipe({
2 name: 'relativeTime',
3 standalone: true
4})
5export class RelativeTimePipe implements PipeTransform {
6 private locale = inject(LOCALE_ID);
7
8 transform(value: Date | string): string {
9 const date = new Date(value);
10 const now = new Date();
11 const diffMs = now.getTime() - date.getTime();
12 const diffMins = Math.floor(diffMs / 60000);
13 const diffHours = Math.floor(diffMs / 3600000);
14 const diffDays = Math.floor(diffMs / 86400000);
15
16 if (diffMins < 1) return 'just now';
17 if (diffMins < 60) return \`\${diffMins} min ago\`;
18 if (diffHours < 24) return \`\${diffHours} hours ago\`;
19 if (diffDays < 7) return \`\${diffDays} days ago\`;
20
21 return date.toLocaleDateString(this.locale);
22 }
23}1@Pipe({
2 name: 'safeAsync',
3 standalone: true,
4 pure: false // Impure - checks on every change detection
5})
6export class SafeAsyncPipe implements PipeTransform, OnDestroy {
7 private subscription?: Subscription;
8 private latestValue: any = null;
9
10 transform<T>(obs: Observable<T>, defaultValue: T): T {
11 if (!this.subscription) {
12 this.subscription = obs.subscribe(value => {
13 this.latestValue = value;
14 });
15 }
16 return this.latestValue ?? defaultValue;
17 }
18
19 ngOnDestroy(): void {
20 this.subscription?.unsubscribe();
21 }
22}
23
24// Usage
25<p>{{ data$ | safeAsync:'Loading...' }}</p>1@Pipe({
2 name: 'filter',
3 standalone: true
4})
5export class FilterPipe implements PipeTransform {
6 transform<T>(items: T[], predicate: (item: T) => boolean): T[] {
7 if (!items || !predicate) return items;
8 return items.filter(predicate);
9 }
10}
11
12// Usage with function
13<div *ngFor="let samurai of samuraiList | filter:isActive">
14 {{ samurai.name }}
15</div>