16 Pipes

Pipes sind ein leistungsstarkes Konzept in Angular, das die Transformation von Daten direkt in Templates ermöglicht. Angular bietet zahlreiche integrierte Pipes und erlaubt die Erstellung eigener, kundenspezifischer Pipes für flexible Datentransformationen.

16.1 Grundlagen

Pipes nehmen Eingabedaten entgegen, transformieren sie und geben das Ergebnis zurück. Die Syntax ist einfach und leicht verständlich:

{{ daten | pipeName:parameter1:parameter2 }}

16.2 Vordefinierte Pipes in Angular

16.2.1 Textformatierung

16.2.1.1 UpperCasePipe und LowerCasePipe

Diese Pipes wandeln Text in Groß- bzw. Kleinbuchstaben um:

<p>{{ "Hallo Welt" | uppercase }}</p> <!-- Ergebnis: HALLO WELT -->
<p>{{ "Hallo Welt" | lowercase }}</p> <!-- Ergebnis: hallo welt -->

16.2.1.2 TitleCasePipe

Formatiert jeden Wortanfang mit einem Großbuchstaben:

<p>{{ "willkommen bei angular" | titlecase }}</p> <!-- Ergebnis: Willkommen Bei Angular -->

16.2.2 Zahlenformatierung

16.2.2.1 DecimalPipe

Formatiert Zahlen mit spezifizierten Dezimalstellen:

<p>{{ 3.14159265 | number:'1.2-4' }}</p> <!-- Ergebnis: 3,1416 (je nach Locale) -->

Die Parameter geben an: - 1: Mindestanzahl von Ganzzahlstellen - 2: Mindestanzahl von Dezimalstellen - 4: Maximalanzahl von Dezimalstellen

16.2.2.2 CurrencyPipe

Die CurrencyPipe bietet Optionen für internationale Währungsformatierung:

<p>{{ 49.99 | currency:'EUR':'symbol':'1.2-2':'de' }}</p> <!-- Ergebnis: 49,99 € -->
<p>{{ 49.99 | currency:'USD':'code':'1.2-2' }}</p> <!-- Ergebnis: USD 49.99 -->

16.2.2.3 PercentPipe

<p>{{ 0.8457 | percent:'1.1-2' }}</p> <!-- Ergebnis: 84,6% (je nach Locale) -->

16.2.3 Datum- und Zeitformatierung

16.2.3.1 DatePipe

Die DatePipe bietet verschiedene Formatierungsoptionen und Unterstützung für verschiedene Zeitzonen:

<p>{{ heute | date:'full':undefined:'de' }}</p> <!-- Vollständiges Datum auf Deutsch -->
<p>{{ heute | date:'dd.MM.yyyy HH:mm' }}</p> <!-- Benutzerdefiniertes Format: 20.03.2025 14:30 -->
<p>{{ heute | date:'medium':'GMT+2' }}</p> <!-- Mit Zeitzonenangabe -->

Die DatePipe unterstützt ISO 8601 Formate und bietet eine API für Zeitzonen.

16.2.4 Array- und Objekt-Pipes

16.2.4.1 SlicePipe

Schneidet Arrays oder Strings basierend auf Start- und Endindex:

<p>{{ [1, 2, 3, 4, 5] | slice:1:4 }}</p> <!-- Ergebnis: [2, 3, 4] -->
<p>{{ "Angular" | slice:0:5 }}</p> <!-- Ergebnis: Angul -->

16.2.4.2 KeyValuePipe

Transformiert ein Objekt oder eine Map in ein Array von key-value Paaren:

<div *ngFor="let item of {name: 'Max', alter: 30} | keyvalue">
  {{item.key}}: {{item.value}}
</div>

16.2.4.3 JsonPipe

Konvertiert ein Objekt in einen JSON-String:

<pre>{{ komplexesObjekt | json }}</pre>

16.2.5 Asynchrone Daten

16.2.5.1 AsyncPipe

Die AsyncPipe abonniert automatisch ein Observable oder Promise und gibt dessen letzten Wert zurück:

<div *ngIf="datenObservable | async as daten">
  {{ daten.name }}
</div>

Sie kümmert sich auch um das Abmelden beim Zerstören der Komponente.

16.3 Verkettung von Pipes

Eine der Stärken von Angular Pipes ist die Möglichkeit, mehrere Pipes zu verketten:

<p>{{ datum | date:'fullDate' | uppercase }}</p>

16.4 Parametrisierung von Pipes

Die meisten Pipes akzeptieren Parameter, die durch Doppelpunkte getrennt werden:

{{ wert | pipe:param1:param2 }}

16.5 Benutzerdefinierte Pipes in Angular

16.5.1 Erstellen einer einfachen Pipe

Um eine eigene Pipe zu erstellen, implementieren Sie das PipeTransform-Interface:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'shorten',
  standalone: true // Für neuere Angular-Versionen
})
export class ShortenPipe implements PipeTransform {
  transform(value: string, maxLength: number = 50): string {
    if (!value) return '';
    
    if (value.length <= maxLength) {
      return value;
    }
    
    return value.substring(0, maxLength) + '...';
  }
}

Verwendung im Template:

<p>{{ langerText | shorten:25 }}</p>

16.5.2 Pure vs. Impure Pipes

16.5.2.1 Pure Pipes (Standard)

@Pipe({
  name: 'filterByCategory',
  pure: true // Standard, kann weggelassen werden
})

Pure Pipes werden nur ausgeführt, wenn: - Der Eingabewert sich ändert (durch Referenzvergleich) - Die Parameter sich ändern

16.5.2.2 Impure Pipes

@Pipe({
  name: 'filterItems',
  pure: false
})
export class FilterItemsPipe implements PipeTransform {
  transform(items: any[], searchTerm: string): any[] {
    if (!items || !searchTerm) {
      return items;
    }
    
    return items.filter(item => 
      item.name.toLowerCase().includes(searchTerm.toLowerCase())
    );
  }
}

Impure Pipes werden bei jedem Change Detection-Zyklus ausgeführt, was sie für Array- oder Objektfilterung nützlich, aber potenziell leistungsintensiv macht.

16.5.3 Eine Pipe mit Dependency Injection

Moderne Angular-Versionen unterstützen verbesserte Dependency Injection:

import { Pipe, PipeTransform, inject } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { map, Observable, startWith, switchMap } from 'rxjs';

@Pipe({
  name: 'smartTranslate',
  standalone: true
})
export class SmartTranslatePipe implements PipeTransform {
  private translateService = inject(TranslateService);
  
  transform(key: string, dynamicParams?: Observable<any>): Observable<string> {
    if (!dynamicParams) {
      return this.translateService.get(key);
    }
    
    return dynamicParams.pipe(
      switchMap(params => this.translateService.get(key, params)),
      startWith('') // Gibt einen Startwert zurück, während auf die Übersetzung gewartet wird
    );
  }
}

Diese Pipe nutzt Dependency Injection mit inject() und gibt ein Observable zurück, das mit AsyncPipe verwendet werden kann.

16.6 Fortgeschrittene Pipe-Features in modernen Angular-Versionen

16.6.1 Signal-Unterstützung

Neuere Angular-Versionen unterstützen Signale in Pipes:

import { Pipe, PipeTransform, Signal, computed } from '@angular/core';

@Pipe({
  name: 'signalTransform',
  standalone: true
})
export class SignalTransformPipe implements PipeTransform {
  transform<T, R>(signal: Signal<T>, fn: (value: T) => R): Signal<R> {
    return computed(() => fn(signal()));
  }
}

Verwendung:

<p>{{ countSignal | signalTransform: value => value * 2 }}</p>

16.7 Best Practices für Pipes in Angular

  1. Verwenden Sie Pure Pipes wann immer möglich Pure Pipes sind wesentlich effizienter, da sie nur bei tatsächlichen Wertänderungen ausgeführt werden.

  2. Vermeiden Sie komplexe Logik in Templates Nutzen Sie Pipes, um komplexe Transformationen aus den Templates zu extrahieren.

  3. TypeScript-Typsicherheit nutzen Angular bietet verbesserte Typsicherheit für Pipes:

    transform(value: string[], searchTerm: string): string[] {
      // Typsichere Implementierung
    }
  4. Standalone Pipes bevorzugen In neueren Angular-Versionen sind Standalone-Komponenten der bevorzugte Weg:

    @Pipe({
      name: 'example',
      standalone: true
    })
  5. Pipes testen Ein einfacher Test für eine Pipe:

    describe('ShortenPipe', () => {
      let pipe: ShortenPipe;
    
      beforeEach(() => {
        pipe = new ShortenPipe();
      });
    
      it('should shorten text longer than maxLength', () => {
        expect(pipe.transform('This is a long text', 10)).toBe('This is a ...');
      });
    
      it('should not modify text shorter than maxLength', () => {
        expect(pipe.transform('Short', 10)).toBe('Short');
      });
    });

16.8 Praxisbeispiel: Filterpipe mit Suchfunktion

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'searchFilter',
  standalone: true
})
export class SearchFilterPipe implements PipeTransform {
  transform<T>(items: T[], searchText: string, property?: keyof T): T[] {
    if (!items || !searchText) {
      return items;
    }
    
    searchText = searchText.toLowerCase();
    
    return items.filter(item => {
      if (property) {
        const value = String(item[property]).toLowerCase();
        return value.includes(searchText);
      } else {
        // Suche in allen String-Properties
        return Object.values(item).some(
          val => typeof val === 'string' && val.toLowerCase().includes(searchText)
        );
      }
    });
  }
}

Verwendung:

<input [(ngModel)]="searchTerm" placeholder="Suche...">

<ul>
  <li *ngFor="let user of users | searchFilter:searchTerm:'name'">
    {{ user.name }} ({{ user.email }})
  </li>
</ul>

Pipes in Angular sind ein leistungsstarkes Werkzeug zur Datentransformation. Mit Funktionen wie der Integration von Signals, verbesserten Standalone-Komponenten und optimierter Leistung sind sie vielseitig einsetzbar. Durch die Kombination vorhandener Pipes und das Erstellen eigener, anwendungsspezifischer Pipes können Entwickler die Datenpräsentation erheblich verbessern und die Lesbarkeit ihrer Templates steigern.