AngularAtlasAusg. 22.2

Kap. 14Fortgeschrittene Reaktivität64 / 75

Zustandsautomaten mit Signals

Keine unmöglichen Zustände mehr: ein typisierter Automat auf Signals, mit Übergängen, Guards und einem Live-Zustandsdiagramm.

Architektur ~0 Min. Lesezeit

Die meisten UI-Bugs sind keine falschen Berechnungen, sondern unmögliche Kombinationen: ein Spinner und eine Fehlermeldung gleichzeitig, ein „Bezahlen“-Button, der noch funktioniert, während die Zahlung läuft, ein Wizard, der einen Schritt übersprungen hat. Sie entstehen, wenn ein Bildschirm mit unabhängigen Booleans beschrieben wird — isLoading, hasError, isPaid. Drei Booleans ergeben acht Kombinationen; der Bildschirm hat vielleicht vier legitime.

Eine Zustandsmaschine dreht die Frage um: Liste die Zustände auf, die es wirklich geben kann, und für jeden die Events, die er akzeptiert. Alles andere wird durch Konstruktion unmöglich, nicht durch Disziplin. Mit Signals sind das etwa dreißig Zeilen und keine Bibliothek.

Warum das wichtig ist
Signals machen abgeleiteten Zustand leicht, aber sie hindern dich nicht daran, zwei Signals zu setzen, die sich widersprechen. Eine Maschine ist die fehlende Regel: Ein Signal hält den Zustand, und ändern kann man ihn nur über eine Transition, die du deklariert hast.

Drei Booleans, acht Kombinationen

Hier die übliche Version. Jeder Handler setzt sein eigenes Flag und vergisst, ein anderes zurückzusetzen — nicht aus Nachlässigkeit, sondern weil nichts dich zwingt, an alle gleichzeitig zu denken. Die Demo unten führt links genau diese Logik aus und rechts eine Maschine.

// ✗ drei unabhängige Flags = 8 Kombinationen; der Bildschirm hat 4 legitime
loading = signal(false);
error = signal<string | null>(null);
data = signal<Order[] | null>(null);

load() {
  this.loading.set(true); // vergessen: error.set(null) — der alte Fehler steht noch da
  this.api.orders().subscribe({
    next: (orders) => this.data.set(orders), // vergessen: loading.set(false)
    error: (e) => this.error.set(e.message), // vergessen: loading.set(false) — Spinner UND Fehler
  });
}
LiveDieselben Events: Booleans vs. eine Maschine

Drei Booleans

loading=false · error=false · data=false

Noch nichts geladen

Erreichte unmögliche Kombinationen: 0

Eine Maschine

state = 'idle'

Noch nichts geladen

Deaktivierte Buttons = Events, die dieser Zustand nicht akzeptiert.

Drücke links LOAD, dann FAIL: Spinner und Fehler erscheinen zusammen. Rechts ist dieselbe Reihenfolge unmöglich — die Buttons, die der aktuelle Zustand nicht akzeptiert, sind deaktiviert.

Der erste Schritt: eine Discriminated Union

Vor jeder Maschine kommt der Zustand in einen Wert, dessen Form von seinem Status abhängt. data gibt es nur bei success und error nur bei error, also lässt sich „ein Fehler zusammen mit Daten“ gar nicht erst schreiben. Im Template verengt @switch den Typ: In @case ('error') ist o.error ein String, nicht vielleicht-undefined.

// ✓ ein Wert; `data` gibt es nur bei success, `error` nur bei error
type Load<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: string };

readonly orders = signal<Load<Order[]>>({ status: 'idle' });

Mit @default never; (Angular 21.2) wird ein neuer Status im Typ, den du im Template vergisst, zum Compile-Fehler. Mehr zum neuen Control Flow unter @if, @for, @switch.

Eine Maschine auf Signals, in dreißig Zeilen

Eine Union sagt, was die Zustände sind; eine Maschine sagt auch, wie du zwischen ihnen wechselst. Das Herz ist eine Tabelle: für jeden Zustand die Events, die er akzeptiert, und wohin jedes führt. send() schaut in die Tabelle; ein Event, das der aktuelle Zustand nicht akzeptiert, wird einfach ignoriert. can() beantwortet dieselbe Frage fürs Template, damit Buttons die Regeln nicht in [disabled] kopieren. Guards fügen Bedingungen auf Daten hinzu, und onEnter bündelt Seiteneffekte an einem Ort.

import { signal } from '@angular/core';

export type Transitions<S extends string, E extends string> = {
  readonly [state in S]: Partial<Record<E, S>>;
};

export interface MachineOptions<S extends string, E extends string> {
  /** zusätzliche Bedingungen: das Event ist nur erlaubt, wenn sein Guard true liefert */
  readonly guards?: Partial<Record<E, (from: S) => boolean>>;
  /** Seiteneffekte beim Betreten eines Zustands — ein Ort für API-Aufrufe, Timer, Analytics */
  readonly onEnter?: Partial<Record<S, () => void>>;
}

export function createMachine<S extends string, E extends string>(
  initial: S,
  transitions: Transitions<S, E>,
  options: MachineOptions<S, E> = {},
) {
  const state = signal<S>(initial);
  const target = (event: E) => transitions[state()][event];
  const can = (event: E) =>
    target(event) !== undefined && (options.guards?.[event]?.(state()) ?? true);

  return {
    state: state.asReadonly(), // niemand kann es von außen .set()
    can, // für [disabled], statt Bedingungen in Templates zu kopieren
    send(event: E): boolean {
      if (!can(event)) return false; // in diesem Zustand nicht erlaubt: nichts passiert
      const next = target(event)!;
      state.set(next);
      options.onEnter?.[next]?.();
      return true;
    },
  };
}

Ein Checkout mit Live-Zustandsdiagramm

Ein Bezahlvorgang ist der klassische Fall: Zurück ist ab Versand erlaubt, aber nicht, während die Zahlung läuft, ohne Adresse kommst du nicht aus dem Versand heraus, und eine abgelehnte Karte braucht einen Weg zurück zum Zahlungsschritt. All das sind Zeilen in einer Tabelle.

LiveCheckout: Zustände, Events, Guards
NEXT NEXT PAY PAID DECLINED BACK BACK RETRY cartshippingpaymentpayingpaidfailed

Zwei Artikel im Warenkorb. NEXT führt zum Versand.

  1. Hier erscheinen jedes Event und die Transition, die es ausgelöst hat.
Geh die Schritte durch. In „shipping“ bleibt NEXT deaktiviert, bis du eine Adresse eingibst (ein Guard). Während „paying“ kann nur die Bank die Maschine bewegen: Versuch BACK. Hake „Karte ablehnen“ an, um den Ausweg aus „failed“ zu sehen.
import { Service, inject, signal } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { createMachine } from './machine';
import { PaymentsApi } from './payments-api';

type Step = 'cart' | 'shipping' | 'payment' | 'paying' | 'paid' | 'failed';
type CheckoutEvent = 'NEXT' | 'BACK' | 'PAY' | 'PAID' | 'DECLINED' | 'RETRY';

@Service()
export class CheckoutStore {
  private readonly payments = inject(PaymentsApi);
  readonly address = signal('');
  readonly error = signal<string | null>(null);

  readonly machine = createMachine<Step, CheckoutEvent>(
    'cart',
    {
      cart: { NEXT: 'shipping' },
      shipping: { NEXT: 'payment', BACK: 'cart' },
      payment: { PAY: 'paying', BACK: 'shipping' },
      paying: { PAID: 'paid', DECLINED: 'failed' }, // kein BACK, kein zweites PAY während der Zahlung
      failed: { RETRY: 'payment' },
      paid: {}, // Endzustand
    },
    {
      guards: {
        // der Guard bekommt den aktuellen Zustand: kein Bezug auf `this.machine` in seiner eigenen Definition
        NEXT: (from) => from !== 'shipping' || this.address().trim() !== '',
      },
      onEnter: { paying: () => void this.pay() },
    },
  );

  private async pay(): Promise<void> {
    try {
      await firstValueFrom(this.payments.charge());
      this.machine.send('PAID');
    } catch (e) {
      this.error.set((e as Error).message);
      this.machine.send('DECLINED');
    }
  }
}

Schau dir den Store an: Das Template entscheidet nie, welche Buttons erlaubt sind, und keine Komponente ruft die Zahlungs-API auf. Die Bank wird an genau einer Stelle aufgerufen — beim Betreten von paying —, also können ein Doppelklick, ein Zurück-Button oder eine Komponente, die zweimal rendert, die Karte nicht doppelt belasten.

Wann eine Bibliothek: XState

Eine handgeschriebene Maschine reicht für einen Ablauf auf einem Bildschirm. Wenn Zustände verschachtelt sind (ein Checkout in einer App, die offline gehen kann), parallel laufen (Upload und Formular gleichzeitig), von Timern abhängen oder du einen visuellen Editor und generierte Tests willst, ist XState die Standardbibliothek für Statecharts. Die Idee bleibt gleich: Zustände, Events, Transitionen. Auch der Verbindungsstatus auf der Seite zu WebSockets ist eine kleine Maschine.

Wann ja, wann nein

Wann ja
  • Mehrstufige Abläufe: Checkout, Onboarding, Wizards, Freigaben.
  • Alles Asynchrone mit sichtbarem Status: Laden, Fehler, Retry, Abbrechen.
  • Controls mit Modi (Ansicht, Bearbeiten, Ziehen, Vorschau) und Verbindungen, die kommen und gehen — siehe WebSockets.
Wann nein
  • Ein einfacher Toggle: Ein boolesches Signal ist perfekt.
  • Aus anderen abgeleitete Werte: Das ist computed(), kein Zustand.
  • Formulare mit unabhängigen Feldern: Jedes Feld ist sein eigener Zustand; die Formularbibliothek kennt valid, dirty und pending schon.

Häufige Stolperfallen

  • Ein Boolean pro Bildschirmteil. Jedes neue Flag verdoppelt die Kombinationen, die niemand getestet hat.
  • Ein Status-String ohne Tabelle. status.set('paid') von überall ist wieder Booleans, nur in einer Variablen.
  • In Templates kopierte Regeln. [disabled]="step === 'paying' || !address" an drei Stellen; frag stattdessen can().
  • Über Komponenten verstreute Seiteneffekte. Zwei Komponenten reagieren auf „paying“, und die Karte wird doppelt belastet. Nimm onEnter, einmal.
  • Ein Zustand ohne Ausweg. „failed“ ohne RETRY oder BACK, und der einzige Ausweg ist, die Seite neu zu laden.

Spickzettel

Symptom              Spinner und Fehler gleichzeitig, ein Button, der geht, wenn er nicht sollte
Ursache              unabhängige Booleans: n Flags = 2^n Kombinationen, die meisten unmöglich
erster Schritt       eine Discriminated Union: { status: 'success'; data } | { status: 'error'; error }
Maschine             ein Zustands-Signal + eine Tabelle  Zustand → { EVENT: nächster Zustand }
send(event)          nur erlaubt, wenn die Tabelle es hat (und der Guard ja sagt); sonst ignoriert
can(event)           für [disabled] und zum Ausblenden von Aktionen, nie doppelte Bedingungen
guards               Bedingungen auf Daten (eine Adresse, ein gültiges Formular) neben der Tabelle
onEnter              Seiteneffekte an EINEM Ort: das Betreten von 'paying' ruft die API auf
Endzustände          {}: aus 'paid' kommt nichts mehr heraus
jeder Zustand        braucht einen Ausweg (failed → RETRY), sonst bleiben Nutzer hängen
abgeleitete Werte    weiterhin computed(); die Maschine entscheidet nur, was passieren KANN
verschachtelt / parallel  Zustände in Zuständen, Timer, ein visueller Editor → XState

Kap. 14 · 0 von 4 abgeschlossen

Lektion abgeschlossen?

Markiere sie, dann erscheint sie auf deiner Karte: im Inhaltsverzeichnis und auf der Startseite.

Wird automatisch markiert, sobald du die ganze Lektion gelesen hast.

  1. Signals unter der Haube
  2. Fortgeschrittenes RxJS: Operatoren höherer Ordnung
  3. NgRx SignalStore
  4. Zustandsautomaten mit Signals
Deine ganze Karte ansehen

Alle 75 Seiten · tippen zum Filtern

  • 01Was ist neu in Angular 21 & 22Alle wichtigen Änderungen in v21 und v22 in Kürze, mit Link zur Seite, die sie jeweils erklärt.Start
  • 01Deine erste App, Schritt für SchrittEine Leseliste, von einer leeren Komponente bis zur fertigen App — Signals, @for, Inputs und Outputs, ein Service und ein Formular, Schritt für Schritt.Start
  • 01Schnelle Entscheidungen„Wohin damit?“, „Signal oder Observable?“, „Shared oder Feature?“ — kurze Antworten auf Alltagsfragen.Start
  • 01Angular-Interviewfragen60 echte Interviewfragen für Junior, Mid und Senior, mit der passenden Antwort, der Nachfrage und den Warnsignalen. Dazu ein Probeinterview.Start
  • 02Standalone & BootstrapWie eine App ohne NgModule startet: bootstrapApplication, app.config.ts, imports in der Komponente.Moderne Grundlagen
  • 02Data Binding & EventsInterpolation, Property- und Attribut-Bindings, Events mit $event und Tastenfiltern und wie [( )] aufgebaut ist — was in das DOM geht und was zurückkommt.Moderne Grundlagen
  • 02Control Flow: @if, @for, @switchDie Block-Syntax, die *ngIf/*ngFor/ngSwitch ersetzt, mit track, @empty und Exhaustive Checks.Moderne Grundlagen
  • 02@let und die neuen Template-AusdrückeLokale Variablen mit @let, Arrow Functions, Spread, Regex, instanceof, Kommentare in Tags.Moderne Grundlagen
  • 02@defer — Lazy Loading in TemplatesSchwere Komponenten nur laden, wenn sie gebraucht werden: Trigger, Prefetch, Placeholder, Loading, Error.Moderne Grundlagen
  • 02Class- & Style-BindingsWarum [class.x] und [style.x] ngClass und ngStyle abgelöst haben (mit automatischer Migration ab v21).Moderne Grundlagen
  • 02Komponenten-Styles & Kapselung:host, die drei Kapselungsmodi, Theming mit CSS-Variablen und warum ::ng-deep der letzte Ausweg ist.Moderne Grundlagen
  • 02Pipes: wann und wiePure vs. Impure Pipes, eigene Pipes und wie du zwischen Pipe, computed() und Methode wählst.Moderne Grundlagen
  • 03signal() und computed()Die reaktiven Grundbausteine: beschreibbarer Zustand, abgeleiteter Zustand, Gleichheit, untracked und Regeln zur Immutability.Signals & Reaktivität
  • 03effect() — wann ja, wann neinMit Signals synchronisierte Seiteneffekte: localStorage, Logging, imperative APIs. Und ihre Stolperfallen.Signals & Reaktivität
  • 03linkedSignal() — editierbarer abgeleiteter ZustandEin Signal, das sich zurücksetzt, wenn sich seine Quelle ändert, das du aber auch manuell setzen kannst.Signals & Reaktivität
  • 03resource, rxResource, httpResourceAsynchrone Daten als Signals: status, value, error, reload, automatischer Abbruch. Stabil seit v22.Signals & Reaktivität
  • 03debounced() — verzögerte SignalsDie „Debounce“-Variante eines Signals, ohne RxJS. Perfekt für die Suche.Signals & Reaktivität
  • 03Listen: suchen, filtern, sortieren, blätternEine Kette von computed-Signals, die nur neu berechnet, was sich geändert hat — mit den Filtern in der URL, damit ein Link dieselbe Ansicht öffnet.Signals & Reaktivität
  • 03Observables von null anWas ein Observable ist, subscribe und unsubscribe, die Operatoren, die du jede Woche brauchst, cold vs. hot — und wann ein Signal reicht.Signals & Reaktivität
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — und wann RxJS weiterhin die richtige Wahl bleibt.Signals & Reaktivität
  • 04input() und output()Inputs als Signals (required, transform, alias) und typisierte Outputs. Daten nach unten, Events nach oben.Komponenten: Kommunikation
  • 04model() — Two-Way-BindingBanana-in-a-Box [( )] mit einer einzigen API. Wann du es nutzt und wann input + output besser ist.Komponenten: Kommunikation
  • 04viewChild & contentChildQueries als Signals: viewChild, viewChildren, contentChild, contentChildren, die Option read.Komponenten: Kommunikation
  • 04Lifecycle & DestroyRefWelche Hooks in der Signals-Ära noch zählen, afterNextRender, DestroyRef und typisiertes ngOnChanges.Komponenten: Kommunikation
  • 04Content Projectionng-content mit select, mehrere Slots, Standardinhalt und die Falle der bedingten Projektion.Komponenten: Kommunikation
  • 04ng-template & ngTemplateOutletTemplates als Werte: Render Props in Angular, typisierter Kontext und Anpassen von Komponenten.Komponenten: Kommunikation
  • 05Smart vs. DumbContainer vs. Presentational: wer den Zustand hält, wer nur anzeigt und wie du die beiden sauber trennst.Komponenten-Design
  • 05Generische Komponenten <T>Eine korrekt typisierte DataTable<T> oder Select<T>, mit Templates für Zellen.Komponenten-Design
  • 05Dynamische KomponentenNgComponentOutlet, createComponent mit inputBinding/outputBinding und ein Dashboard, das aus einer Konfiguration gebaut wird.Komponenten-Design
  • 05Direktiven & Host-KompositionAttribut-Direktiven, die host: {}-Metadaten und die Directive Composition API (hostDirectives).Komponenten-Design
  • 05Eigene Formular-ControlsFormValueControl (Signal Forms) vs. ControlValueAccessor: eine Sternebewertung, in beiden Varianten.Komponenten-Design
  • 05Change DetectionOnPush ist ab v22 der Standard, zone.js entfällt ab v21. Was das Rendering auslöst und wie du dir nicht die Finger verbrennst.Komponenten-Design
  • 06inject() & @Service()Der neue @Service()-Decorator ab v22, inject() vs. Konstruktor und der Injection-Kontext.Dependency Injection
  • 06Provider & die Injector-HierarchieRoot vs. Route vs. Komponente, useClass/useValue/useFactory/useExisting und die Modifier optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Typisierte Konfiguration, provideFeature()-Funktionen, makeEnvironmentProviders und Initializer.Dependency Injection
  • 06injectAsync() — Lazy ServicesLade einen schweren Service erst, wenn du ihn brauchst, mit Prefetch im Leerlauf.Dependency Injection
  • 07Ordnerstrukturcore / shared / features, was in welchen Ordner gehört und wie ein Feature von innen aussieht.Architektur der Anwendung
  • 07Shared vs. FeatureWann du eine Komponente nach Shared verschiebst und (vor allem) wann NICHT. Eine konkrete Checkliste.Architektur der Anwendung
  • 07Interfaces & ModelleInline-Interface oder eigene Datei? DTO vs. Domänenmodell, type vs. interface, wohin damit.Architektur der Anwendung
  • 07State Management mit SignalsEinfache Signal-Stores, Fassaden, lokaler vs. globaler Zustand und wann du NgRx brauchst.Architektur der Anwendung
  • 07Styleguide & NamensgebungDie aktuellen offiziellen Konventionen: Dateinamen ohne Suffixe, protected, readonly, Reihenfolge der Member.Architektur der Anwendung
  • 07Barrels, Aliase & Grenzenindex.ts, Pfad-Aliase, die öffentliche API eines Features und Abhängigkeitsregeln, die sich automatisch prüfen lassen.Architektur der Anwendung
  • 07Fehler: @boundary & ErrorHandlerDer neue @boundary-Block ab v22.2, der globale ErrorHandler, HTTP-Fehler und Fehler aus resource.Architektur der Anwendung
  • 08Modernes Routing & Lazy LoadingloadComponent, Child Routes, Parameter als Inputs und Parameter-Vererbung (neuer Standard in v22).Routing
  • 08Guards & ResolvercanActivate, canMatch, canDeactivate und resolve als Funktionen, mit Redirects über UrlTree / RedirectCommand.Routing
  • 09Signal Forms — die GrundlagenFormulare auf Basis von Signals: form(), [formField], schemabasierte Validierung. Stabil seit v22.Formulare
  • 09Signal Forms — fortgeschrittenEigene und feldübergreifende Validierung, async/HTTP mit Debounce, dynamische Listen, disabled/hidden, wiederverwendbare Schemas.Formulare
  • 09Typisierte Reactive FormsTypisierte FormGroup, nonNullable, FormArray — und wie sie neben Signal Forms bestehen.Formulare
  • 10HttpClient, Interceptors & die API-SchichtHttpClient ohne Setup (v21), Fetch als Standard (v22), funktionale Interceptors und eine API-Schicht mit DTO-Mapping.HTTP & Daten
  • 11Performance — eine ChecklisteWas wirklich zählt: OnPush + Signals, track, @defer, Lazy Routes, Bilder, Bundles und Hydration.Qualität & Performance
  • 11Testen mit VitestVitest ist ab v21 der Standard-Runner. TestBed, Komponenten mit Signals, Services, HTTP und Harnesses.Qualität & Performance
  • 11DevTools: ein Blick in deine AppChrome DevTools und Angular DevTools Schritt für Schritt: was jedes Panel zeigt, mit Übungen, die auf dieser Website funktionieren.Qualität & Performance
  • 11Angular AriaHeadless, barrierefreie Komponenten, die du nach Belieben stylst: Tabs, Accordion, Menü, Listbox...Qualität & Performance
  • 12SSR, Prerendering & Render ModesWann auf dem Server gerendert wird, wann beim Build und wann nur im Browser: RenderMode pro Route, app.routes.server.ts und die echten Kosten.SSR & Hydration
  • 12Hydration: Event Replay & inkrementellWie der Browser das Server-HTML übernimmt, ohne es neu zu rendern: vollständige Hydration, Event Replay, @defer (hydrate on …) und Mismatch-Fehler.SSR & Hydration
  • 12Servertauglicher Codewindow gibt es auf dem Server nicht: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, der HTTP-Cache und PendingTasks.SSR & Hydration
  • 13Micro FrontendsWann es sich lohnt, eine App in mehrere Deployments aufzuteilen und wann es nur Komplexität ist: Native Federation, Module Federation, iframes, Web Components.Architektur im großen Maßstab
  • 13Web Components mit Angular ElementscreateCustomElement: eine Angular-Komponente, die überall als HTML-Tag nutzbar ist, plus Kommunikation zwischen Apps über Events und BroadcastChannel.Architektur im großen Maßstab
  • 13Monorepo, Bibliotheken & GrenzenEin Workspace mit mehreren Apps und Bibliotheken: ng generate library, Nx, Secondary Entry Points, Publishing und Abhängigkeitsregeln.Architektur im großen Maßstab
  • 13Hexagonale Architektur (Ports & Adapters)Eine Domäne ohne Angular, Ports als abstrakte Klassen und austauschbare Adapter: HTTP, localStorage oder In-Memory, ohne die UI anzufassen.Architektur im großen Maßstab
  • 14Signals unter der HaubeDer reaktive Graph: Producer und Consumer, Push-Pull, warum computed lazy und glitch-frei ist, das Diamond-Problem und wann Effects laufen.Fortgeschrittene Reaktivität
  • 14Fortgeschrittenes RxJS: Operatoren höherer OrdnungswitchMap, mergeMap, concatMap und exhaustMap an einem Live-Diagramm, dazu Retry mit Backoff, shareReplay und wie du Leaks vermeidest.Fortgeschrittene Reaktivität
  • 14NgRx SignalStoreState Management im großen Stil auf Signals: withState, withComputed, withMethods, rxMethod, Entities und Hooks — und wann ein einfacher Store reicht.Fortgeschrittene Reaktivität
  • 14Zustandsautomaten mit SignalsKeine unmöglichen Zustände mehr: ein typisierter Automat auf Signals, mit Übergängen, Guards und einem Live-Zustandsdiagramm.Fortgeschrittene Reaktivität
  • 15WebSockets: Echtzeit, die das Netz überstehtEin typisierter Socket als Signals: Reconnect mit Backoff und Jitter, Heartbeat, ein Postausgang im Offline-Modus und SSR-Sicherheit.Echtzeit & offline
  • 15Optimistische Updates & RollbackEine sofortige UI, die ehrlich bleibt: Snapshot und Rollback, Antworten in falscher Reihenfolge, Idempotenzschlüssel.Echtzeit & offline
  • 15Offline-first: Service Worker & CachingDer Angular Service Worker: Caching-Strategien, Update-Hinweise und ein Postausgang für Änderungen, die offline entstehen.Echtzeit & offline
  • 16Web WorkersSchwere Berechnungen, ohne die UI zu blockieren: ein echter Worker in der Seite, Message Passing und wann es sich nicht lohnt.Fortgeschrittene UI & Performance
  • 16Riesige Listen: Virtual Scroll100.000 Zeilen ohne Ruckeln: CDK Virtual Scroll, itemSize, trackBy und die Alternativen (Paginierung, Infinite Scroll).Fortgeschrittene UI & Performance
  • 16Moderne Animationen & View Transitionsanimate.enter und animate.leave statt des veralteten @angular/animations, CSS-Transitions und View Transitions bei der Navigation.Fortgeschrittene UI & Performance
  • 16Memory Leaks finden und behebenSubscriptions, Timer und Listener, die ihre Komponente überleben – wie du sie in den DevTools findest und schließt.Fortgeschrittene UI & Performance
  • 17Sicherheit: XSS, Sanitizing & CSPWas Angular automatisch gegen XSS tut, wann bypassSecurityTrust gefährlich wird, dazu CSP mit Nonce, Trusted Types und XSRF.Sicherheit & Globalisierung
  • 17Authentifizierung: Tokens & RefreshEin Interceptor, der das Token anhängt, bei 401 einmal erneuert und die wartenden Requests wiederholt — dazu, wo du das Token aufbewahrst.Sicherheit & Globalisierung
  • 17OAuth 2.1 & OpenID Connect mit PKCEDer Authorization-Code-Flow mit PKCE Schritt für Schritt: Verifier und Challenge, State und Nonce, das ID-Token und warum ein BFF sicherer ist.Sicherheit & Globalisierung
  • 17Internationalisierung (i18n)$localize, das i18n-Attribut, ICU plural/select, ein Build pro Sprache vs. Übersetzungen zur Laufzeit und Formatierung nach Locale.Sicherheit & Globalisierung