AngularAtlasAusg. 22.2

Kap. 14Fortgeschrittene Reaktivität62 / 75

Fortgeschrittenes RxJS: Operatoren höherer Ordnung

switchMap, mergeMap, concatMap und exhaustMap an einem Live-Diagramm, dazu Retry mit Backoff, shareReplay und wie du Leaks vermeidest.

Architektur ~0 Min. Lesezeit Offizielle Doku

Signals haben den Zustand übernommen, aber Ereignisse über die Zeit bleiben das Revier von RxJS: Tastenanschläge, Klicks, sich überlappende Requests, Retries, Websockets. Der wichtigste Teil, und der am häufigsten falsch gemachte, sind die Higher-Order-Operatoren. Jeder Wert startet ein neues Observable, meist einen HTTP-Request. Die eigentliche Frage lautet: Was tust du, wenn der nächste Wert eintrifft, während der vorherige Request noch läuft?

Es gibt vier Antworten: abbrechen, parallel ausführen, in die Warteschlange stellen oder ignorieren. Jede hat ihren Operator. Wählst du falsch, entsteht ein Race-Condition-Bug: alte Ergebnisse überschreiben die neuen, Bestellungen werden doppelt abgeschickt, Speichervorgänge laufen in der falschen Reihenfolge.

Warum das wichtig ist
„Die Suche zeigt manchmal Ergebnisse für den vorherigen Text“ oder „die Bestellung wurde zweimal gesendet“ sind fast immer ein mergeMap, wo ein switchMap oder exhaustMap nötig gewesen wäre. Der Unterschied zeigt sich nicht in schnellen Tests, sondern erst in einem langsamen Netzwerk. Genau das kannst du in der Demo unten nachstellen.

Das Problem: Observable von Observables

Ein map, das einen Request zurückgibt, erzeugt ein Observable<Observable<T>>: einen Stream von Requests, die niemand abonniert hat. Die *Map-Operatoren abonnieren die inneren Streams selbst und flachen sie zu einem einzigen Stream von Ergebnissen ab. Der Unterschied zwischen ihnen ist nur die Überlappungsstrategie.

// „Für jeden Wert ein Observable starten“ — die Frage ist, was du tust, wenn der nächste Wert eintrifft,
// während der vorherige noch läuft.
clicks$.pipe(map((id) => http.get(`/api/items/${id}`)));       // ✗ Observable<Observable<Item>>
clicks$.pipe(switchMap((id) => http.get(`/api/items/${id}`))); // ✓ Observable<Item> — plus eine Strategie

Die vier Operatoren

OperatorEin neuer Wert trifft ein, während der alte läuftTypisches Beispiel
switchMapbricht den alten ab (Unsubscribe → HttpClient bricht den Request ab)Typeahead, Route-Parameter
mergeMapführt sie parallel aus; die Reihenfolge der Ergebnisse ist nicht garantiertunabhängige Uploads
concatMapstellt ihn in die Warteschlange; läuft nacheinander, der Reihe nachAutosave, geordnete Befehle
exhaustMapignoriert ihn, bis der aktuelle fertig istSubmit, Login
// Typeahead: Nur der letzte Request zählt; die alten werden ABGEBROCHEN (HttpClient bricht auch das XHR/fetch ab)
readonly results = toSignal(
  this.query$.pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap((q) => this.api.search(q).pipe(catchError(() => of([])))),
  ),
  { initialValue: [] },
);
LiveLive-Marble-Diagramm (echte RxJS-Operatoren)

switchMap: Ein neuer Klick BRICHT den laufenden Request AB. Ideal für die Suche (Typeahead) und Route-Parameter.

Klicks (outer)
Requests (inner)
Ergebnis (output)
emittiert: 0geliefert: 0abgebrochen: 0
Wähle einen Operator und drücke mehrmals auf „Emittieren“, schneller als ein Request dauert. switchMap kappt die alten Balken (✕), mergeMap überlappt sie, concatMap reiht sie hintereinander, exhaustMap ignoriert die während eines Requests ausgelösten.

Wohin mit catchError

Ein Fehler beendet den Stream, in dem er auftritt. Steht catchError nach dem switchMap, schließt der erste fehlgeschlagene Request den gesamten Stream: Die Suche reagiert nicht mehr, ohne dass in der Konsole ein Fehler erscheint. Setze es in die innere Projektion. Dann wird nur dieser Request durch einen Ersatzwert ersetzt, und der äußere Stream läuft weiter.

// ✗ catchError NACH switchMap: Der erste Fehler beendet den äußeren Stream — die Suche „stirbt“
query$.pipe(
  switchMap((q) => api.search(q)),
  catchError(() => of([])),
);

// ✓ catchError IN der Projektion: Nur dieser Request schlägt fehl, der äußere Stream bleibt am Leben
query$.pipe(
  switchMap((q) => api.search(q).pipe(catchError(() => of([])))),
);

Retry mit exponentiellem Backoff

retry({ count, delay }) abonniert die Quelle nach einem Fehler erneut. Die Funktion delay erhält den Fehler und die Nummer des Versuchs und gibt ein Observable zurück, das bestimmt, wann wiederholt wird. Wird die Pause bei jedem Schritt verdoppelt (300, 600, 1200 ms …), hämmerst du nicht auf den Server ein, solange er Probleme hat. Wirf den Fehler weiter, wenn er sich nicht von selbst beheben wird (401, 404). Bei HTTP sitzt der Retry meist in einem Interceptor (siehe HttpClient & Interceptors). Für eine Verbindung, die Server-Neustarts überstehen muss — mit Jitter, damit nicht tausend Clients in derselben Sekunde zurückkommen —, siehe WebSockets.

import { retry, timer } from 'rxjs';

http.get('/api/report').pipe(
  retry({
    count: 4,                                                // höchstens 4 Retries
    delay: (error, retryCount) => {
      if (error.status === 401 || error.status === 404) throw error; // „endgültige“ Fehler nicht wiederholen
      return timer(300 * 2 ** (retryCount - 1));              // 300, 600, 1200, 2400 ms
    },
    resetOnSuccess: true,
  }),
);
Liveretry mit Backoff, auf einer Quelle, die ausfällt
  1. Drücke den Button.
Lege fest, wie oft der Server fehlschlägt und wie viele Retries du erlaubst. Das Log zeigt die wachsenden Pausen. Übersteigen die Fehlschläge count, erhältst du den endgültigen Fehler.

share und shareReplay

Ein „kaltes“ Observable wie http.get wird bei jedem Subscribe ausgeführt. Drei Subscriber bedeuten drei Requests. share() sorgt dafür, dass gleichzeitige Subscriber sich eine einzige Ausführung teilen. shareReplay behält zusätzlich den letzten Wert für alle, die später dazukommen, und funktioniert so wie ein Cache. Die Falle ist ein einfaches shareReplay(1): Es hat refCount: false und beendet daher nie das Abonnement der Quelle. Bei einem Stream, der nie endet (Websocket, Interval), läuft die Quelle weiter, nachdem alle Subscriber gegangen sind.

Ein feiner Punkt bei refCount: true: Der Cache bleibt nur erhalten, wenn die Quelle noch abschließen konnte. Gehen alle Subscriber vor complete (zum Beispiel bei firstValueFrom, take(1) oder einer Komponente, die während des Requests zerstört wird), beendet shareReplay das Abonnement der Quelle und beginnt beim nächsten Subscriber von vorn.

// Ohne Sharing: Jedes Subscribe = eine weitere Ausführung (ein weiterer Request)
const user$ = http.get<User>('/api/me');
user$.subscribe(); user$.subscribe();                 // 2 Requests

// share(): GLEICHZEITIGE Subscriber teilen sich eine Ausführung; nach complete wird zurückgesetzt
const shared$ = http.get<User>('/api/me').pipe(share());

// shareReplay: behält den letzten Wert für SPÄTE Subscriber (Cache)
const cached$ = http.get<User>('/api/me').pipe(shareReplay({ bufferSize: 1, refCount: true }));
// refCount: true → Geht der letzte Subscriber, beendet es auch das Abonnement der Quelle.
// shareReplay(1) (refCount: false) auf einer Quelle, die nie abschließt = die Quelle läuft ewig.
LiveWie viele Ausführungen? Und wer bleibt abonniert?
3 gleichzeitige Subscriber + 1 später Subscriber bei einem „Request“ von 400 ms; danach ein unendlicher Stream, von dem sich alle abmelden.
Variante Request-Ausführungen Später Subscriber Unendlicher Stream nach Unsubscribe
Drücke „Szenario starten“ (dauert ca. 2 s).
Das Szenario läuft mit echtem RxJS: dieselben 3 gleichzeitigen Subscriber und 1 später, danach ein unendlicher Stream, von dem sich alle abmelden. Nur shareReplay(1) lässt die Quelle weiterlaufen. Die Demo-Quellen werden am Ende gestoppt.

Streams kombinieren

combineLatest emittiert, sobald sich irgendeine Quelle ändert, nachdem jede mindestens einmal emittiert hat. Es eignet sich für kombinierte Filter. withLatestFrom emittiert nur über die Hauptquelle und holt sich den aktuellen Wert aus den anderen („beim Klick das aktuelle Formular speichern“). forkJoin wartet, bis alle abgeschlossen sind, und emittiert einmal: Es ist ein Promise.all für Requests.

// combineLatest: emittiert bei jeder Änderung, nachdem ALLE einmal emittiert haben — kombinierte Filter
combineLatest([category$, sort$]).pipe(switchMap(([c, s]) => api.list(c, s)));

// withLatestFrom: emittiert nur über die Hauptquelle und nimmt den letzten Wert der anderen
save$.pipe(withLatestFrom(form$), concatMap(([, value]) => api.save(value)));

// forkJoin: wartet, bis ALLE abgeschlossen sind, eine einzige Emission — unabhängige parallele Requests
forkJoin({ user: api.me(), settings: api.settings() });

// zip: paart den n-ten Wert jeder Quelle — in einer UI selten nützlich

Keine vergessenen Subscriptions

Jedes manuelle subscribe in einer Komponente muss geschlossen werden. takeUntilDestroyed() erledigt das automatisch, wenn die Komponente zerstört wird. Für Werte, die im Template angezeigt werden, ist toSignal() noch einfacher: Es abonniert und beendet das Abonnement von selbst (siehe Signals ↔ RxJS).

import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

export class Live {
  constructor() {
    interval(1000)
      .pipe(takeUntilDestroyed()) // in einem Injection-Kontext; sonst: takeUntilDestroyed(this.destroyRef)
      .subscribe((n) => this.tick.set(n));
  }
}
// Für Zustand, der im Template angezeigt wird, beendet toSignal(obs$) das Abonnement selbst (siehe Seite Signals ↔ RxJS).

Wann ja, wann nein

RxJS ist das richtige Werkzeug
  • Ereignisse über die Zeit: Debounce, Throttle, Zeitfenster, Kombination mehrerer Quellen.
  • Requests, die sich überlappen können und eine Strategie brauchen: Abbrechen, Warteschlange, Ignorieren.
  • Retries, Timeouts, Polling, Websockets, Server-Sent Events.
  • Geordnete Befehlsabläufe (Autosave, Offline-Warteschlangen).
Signals / resource reichen aus
  • Zustand, der in der UI angezeigt wird: signal / computed (siehe Signals).
  • Ein Request, der von Parametern abhängt: httpResource / rxResource brechen veraltete Requests selbst ab (siehe resource).
  • Ein einzelner Request pro Klick, ohne mögliche Überlappung: ein einfaches subscribe oder eine async-Methode.
  • „Um es reaktiv zu machen“: Ein BehaviorSubject für einen einfachen Wert ist heute ein signal().

Häufige Stolperfallen

  • mergeMap für die Suche. Antworten treffen in beliebiger Reihenfolge ein, und eine alte kann die neue überschreiben. Nimm switchMap.
  • switchMap für Speichervorgänge. Ein auf halbem Weg abgebrochener Save wurde vom Server vielleicht schon verarbeitet, vielleicht auch nicht. Für Schreibvorgänge nimm concatMap oder exhaustMap. Mehr zu Schreibvorgängen in falscher Reihenfolge unter optimistische Updates.
  • Subscribe in Subscribe. Du verlierst Abbruch und Fehlerbehandlung. Jedes „subscribe, und dann im Callback ein weiteres subscribe“ ist ein *Map-Operator.
  • catchError auf der äußeren Ebene eines Streams, der am Leben bleiben muss: Es stoppt alles beim ersten Fehler.
  • shareReplay(1) auf unendlichen Quellen: Speicher- und Verbindungs-Leaks. Verwende { bufferSize: 1, refCount: true }. Wie du sie findest, zeigt die Seite zu Memory Leaks.
  • Retry bei 4xx: Du wiederholst endlos einen Request, der nie gelingen wird. Filtere nach Status.

Spickzettel

OPERATOR      WENN EIN NEUER WERT EINTRIFFT, WÄHREND DER ALTE LÄUFT  EINSATZ
switchMap     den alten abbrechen                                    Suche, Route-Parameter, „der letzte gewinnt“
mergeMap      parallel ausführen (optional: Concurrency)             unabhängige Operationen, Uploads
concatMap     in die Warteschlange, der Reihe nach                   geordnetes Speichern, Befehlsschlangen
exhaustMap    ignorieren                                             Submit, Login, manuelles Refresh

catchError    IN der inneren Projektion, damit der äußere Stream am Leben bleibt
retry         { count, delay: (err, n) => timer(base * 2 ** (n - 1)) } — 4xx nicht wiederholen
share()       gleichzeitige Subscriber teilen sich die Ausführung
shareReplay   { bufferSize: 1, refCount: true } — Cache + korrektes Beenden des Abonnements
combineLatest kombinierte Filter · withLatestFrom „beim Klick den aktuellen Wert nehmen“ · forkJoin „alle, einmal“
takeUntilDestroyed() / toSignal()   keine vergessenen Subscriptions

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