Eine Pipe transformiert einen Wert für die Anzeige, direkt im Template: {{ price | currency }}. Sie ist eine wiederverwendbare reine Funktion, die du wie jede Komponente importierst. Standardmäßig sind Pipes pure: Angular führt sie nur erneut aus, wenn sich der Eingabewert oder die Argumente ändern.
Eingebaute Pipes und eigene Pipes
<p>{{ order().createdAt | date: 'dd MMM yyyy, HH:mm' }}</p>
<p>{{ order().total | currency: 'RON' : 'symbol' : '1.2-2' }}</p>
<p>{{ ratio() | percent: '1.0-1' }}</p>
<p>{{ user().name | initials }}</p> <!-- eigene Pipe -->
<p>{{ post().publishedAt | timeAgo }}</p>
@for (entry of config() | keyvalue; track entry.key) {
<dt>{{ entry.key }}</dt><dd>{{ entry.value }}</dd>
}
<!-- async: abonniert und kündigt selbst (nützlich, solange du noch Observables hast) -->
@let user = user$ | async;date: 'fullDate' | joi, 22 octombrie 2026 |
date: 'HH:mm' | 09:11 |
currency: 'RON' | 1.234,50 RON |
currency: 'EUR' : 'symbol' : '1.0-0' | 247 EUR |
number: '1.2-2' | 411,50 |
percent | 18,8 % |
initials (custom) | AM |
timeAgo (custom) | vor 5 Std. |
keyvalue | limba=ronotificari=truetema=dark |
So schreibst du eine Pipe
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'timeAgo' }) // standardmäßig standalone, standardmäßig pure
export class TimeAgoPipe implements PipeTransform {
transform(value: Date | string | number, now: number = Date.now()): string {
const seconds = Math.round((now - new Date(value).getTime()) / 1000);
if (seconds < 45) return 'gerade eben';
const minutes = Math.round(seconds / 60);
if (minutes < 60) return `vor ${minutes} Min.`;
const hours = Math.round(minutes / 60);
if (hours < 24) return `vor ${hours} Std.`;
const days = Math.round(hours / 24);
return days === 1 ? 'gestern' : `vor ${days} Tagen`;
}
}Lokale Formatierung (ro-RO)
// Formatierung auf Rumänisch für date, currency, number
import { registerLocaleData } from '@angular/common';
import localeRo from '@angular/common/locales/ro';
import { LOCALE_ID } from '@angular/core';
registerLocaleData(localeRo);
export const appConfig: ApplicationConfig = {
providers: [
{ provide: LOCALE_ID, useValue: 'ro' },
{ provide: DEFAULT_CURRENCY_CODE, useValue: 'RON' },
],
};Pipe vs. Methode vs. computed()
Eine Methode, die aus dem Template aufgerufen wird, läuft bei jeder Change Detection der Komponente. Eine pure Pipe und ein computed() sind memoisiert: Sie laufen nicht erneut, wenn sich ihre Eingaben nicht geändert haben.
// So entscheidest du:
//
// ANZEIGE-Transformation, in vielen Komponenten genutzt → Pipe (date, currency, initials, timeAgo)
// Berechnung nur für eine Komponente, auf ihren Signals → computed()
// Fachlogik / Ableitung von Zustand → computed() / Store
// Methode, die aus dem Template aufgerufen wird → nur für Triviales
//
// Warum keine Methode? Sie wird bei jeder Change Detection der Komponente aufgerufen.
// Die pure Pipe und das computed() werden nur neu berechnet, wenn sich ihre Eingaben ändern.Impure Pipes
// Impure Pipe: läuft bei JEDER Change Detection, egal welche Eingabe
@Pipe({ name: 'filterBy', pure: false })
export class FilterByPipe implements PipeTransform {
transform<T>(items: T[], predicate: (item: T) => boolean): T[] {
return items.filter(predicate); // läuft oft → bei großen Listen vermeiden
}
}
// Fast immer ist ein computed() in der Komponente die richtige Wahl:
readonly activeUsers = computed(() => this.users().filter((u) => u.active));Hängt der Wert von Signals ab, ist ein computed() meist einfacher als eine Pipe: siehe signal() und computed(). Datums- und Zahlenformatierung je Locale steht unter {i18n}.
Wann ja, wann nein
- Anzeigeformatierung, die an mehreren Stellen genutzt wird (relatives Datum, Dateigröße, Initialen, IBAN-Maskierung).
- Eine pure Transformation: gleiche Eingabe → gleiche Ausgabe.
- Du willst sie auch in Templates nutzen, die keine eigene Logikklasse haben (z. B. Dumb-Komponenten).
- Eine Berechnung, die nur zu einer Komponente gehört →
computed(). - Fachdaten filtern/sortieren →
computed()oder ein Store. - Du brauchst HTTP oder Zustand → eine Pipe ist dafür der falsche Ort (nimm resource / einen Service).
- Eine impure Pipe, „damit es läuft“ → du brauchst mit ziemlicher Sicherheit ein Signal.
Häufige Stolperfallen
- Du mutierst ein Array und wunderst dich, warum die pure Pipe nicht neu läuft: Die Referenz ist dieselbe. Erzeuge ein neues Array.
- Du vergisst den Import: „The pipe 'date' could not be found“ → füge
DatePipezuimportshinzu. - Nicht registrierte Locale:
LOCALE_ID = 'ro'ohneregisterLocaleData(localeRo)wirft einen Fehler. - Bei jedem Rendern neue Argumente (
| pipe: { a: 1 }) heben die Memoisierung in manchen Fällen auf. Halte die Argumente stabil.