AngularAtlasAusg. 22.2

Kap. 14Fortgeschrittene Reaktivität61 / 75

Signals unter der Haube

Der reaktive Graph: Producer und Consumer, Push-Pull, warum computed lazy und glitch-frei ist, das Diamond-Problem und wann Effects laufen.

Architektur ~0 Min. Lesezeit Offizielle Doku

Auf der Seite signal() und computed() hast du gesehen, was Signals tun. Diese Seite zeigt, wie sie im Inneren funktionieren: ein reaktiver Graph, der automatisch aus Lesezugriffen aufgebaut wird. Schreibzugriffe schicken nur eine Benachrichtigung, neu berechnet wird erst, wenn jemand liest. Daraus ergeben sich alle nützlichen Eigenschaften: computed ist lazy und memoisiert, du siehst nie inkonsistente Zwischenzustände, und Angular kann nur die betroffenen Komponenten neu rendern, ohne Zone.js.

Warum das wichtig ist
Wenn du das Modell verstanden hast, kannst du vieles selbst erschließen: warum ein teures computed nichts kostet, solange es niemand liest, warum items().push() die UI nicht aktualisiert, warum ein effect, der ein anderes Signal setzt, eine schlechte Idee ist, oder warum ein Signal, das in einem if-Zweig gelesen wird, manchmal „nicht reagiert“.

Producer, Consumer und der Graph

Jedes Signal ist ein Knoten im Graphen. signal() ist ein Producer. computed() ist beides: Consumer (es liest andere Signals) und Producer (andere lesen es). effect() und Component-Templates sind Consumer. Solange eine reaktive Funktion läuft, gibt es einen aktiven Consumer, und jedes Signal, das in diesem Moment gelesen wird, wird zu seiner Abhängigkeit. Der Graph wird nicht deklariert: Er entsteht aus Lesezugriffen.

Jeder Knoten hat eine version, die nur steigt, wenn er einen Wert erzeugt, der sich vom vorherigen unterscheidet. Manche Consumer sind „live“ (Effects und Templates); für sie führt der Graph zusätzlich umgekehrte Kanten vom Producer zum Consumer, um ihnen Benachrichtigungen zu schicken. Die Primitive-Typen in @angular/core/primitives/signals zeigen genau diese Felder: version, dirty, producers, consumers.

const a = signal(1);                                  // Producer
const b = signal(2);                                  // Producer
const sum = computed(() => a() + b());                // Consumer UND Producer
const product = computed(() => a() * b());
const result = computed(() => sum() + product());     // Diamant: a und b kommen hier auf zwei Wegen an

// Während eine reaktive Funktion läuft, merkt sich Angular einen „aktiven Consumer“.
// Jedes Signal, das in diesem Moment gelesen wird, wird zu seiner Abhängigkeit. Du deklarierst nichts: Der Graph entsteht aus Lesezugriffen.

Erst Push, dann Pull

Ein Schreibzugriff (set/update) berechnet nichts neu. Er erhöht nur die Version des Signals und meldet den Live-Consumern, dass sie dirty sein könnten: Das ist die Push-Phase. Wenn der Consumer wieder läuft (das Template beim nächsten Rendering, der Effect, wenn er an der Reihe ist), liest er, was er braucht, und jedes computed prüft seine Producer: Hat sich irgendeine Version geändert? Nur dann wird neu berechnet. Das ist die Pull-Phase.

a.set(5)
  │  PUSH: a erhöht seine `version` und meldet den „Live“-Consumern (Template, Effect), dass sie dirty SEIN KÖNNTEN.
  │        Noch wird nichts neu berechnet.
  ▼
Template / Effect als dirty markiert  →  Change Detection plant ein Rendering
  │
  ▼
Template liest result()
  │  PULL: result prüft seine Producer (sum, product) — haben sie eine andere Version?
  │        sum prüft seine Producer (a, b) — a hat eine andere Version → sum wird neu berechnet.
  │        Ist der neue Wert GLEICH dem alten, steigt die Version von sum nicht → die Propagation stoppt.
  ▼
result wird einmal neu berechnet, mit bereits konsistenten Werten (glitch-free)

Die wichtige Konsequenz: Ein computed wird erst neu berechnet, nachdem alle Schreibzugriffe abgeschlossen sind, und zwar mit bereits konsistenten Werten. Im Diamanten der Demo sieht result nie ein neues sum mit einem alten product. Das nennt man glitch-free. Und wenn du a und b im selben Klick änderst, wird result nur einmal neu berechnet.

LiveDer reaktive Graph, instrumentiert (echte Signals)
a = 1signalb = 2signal sum = berechnet × product = berechnet × result = berechnet × template Consumer

Im Template: a = 1, b = 2 · result = 5

Was result bei jeder Neuberechnung „gesehen“ hat:
    Klicke auf „a + 1“: sum, product und result werden jeweils einmal neu berechnet. Klicke auf den Button, der beide ändert: trotzdem nur eine Neuberechnung. Entferne den Haken bei „das Template liest result“ und ändere a: Es wird nichts mehr berechnet (lazy). Das Log zeigt, dass result immer konsistente Paare sieht.

    Laziness und Memoisierung

    Die Angular-Dokumentation sagt es direkt: Ein computed wird lazy ausgewertet und memoisiert. Die Funktion läuft erst beim ersten Lesen. Danach wird der Wert gespeichert und wiederverwendet, bis sich eine Abhängigkeit ändert. In der Praxis kannst du teure Ableitungen (Filtern, Sortieren) in ein computed legen: Sie kosten nur dann etwas, wenn das Ergebnis tatsächlich gebraucht wird.

    const expensive = computed(() => {
      console.log('berechne…');
      return items().filter(matches).sort(byPrice);
    });
    
    items.set(newItems);  // nichts wird ausgegeben: noch hat niemand gelesen
    expensive();          // „berechne…“ — erster Lesezugriff
    expensive();          // nichts: memoisierter Wert
    items.set(other);     // weiterhin nichts — als veraltet markiert, nicht neu berechnet
    expensive();          // „berechne…“

    Gleichheit: Wo die Propagation stoppt

    Die Version eines Knotens steigt nur, wenn der neue Wert nicht „gleich“ dem alten ist. Standardmäßig ist die Gleichheit Object.is: Bei Objekten und Arrays zählt die Referenz, nicht der Inhalt. Derselbe Mechanismus gilt auch für ein computed. Ändert sich sein Ergebnis nicht, werden seine Consumer nicht neu berechnet, selbst wenn sich seine Abhängigkeiten geändert haben. Mit { equal } legst du fest, was „dasselbe“ bedeutet.

    // Standardmäßig: Object.is. Bei Objekten/Arrays zählt die REFERENZ.
    const tags = signal(['a', 'b']);
    tags.set(['a', 'b']);           // andere Referenz → „neuer“ Wert → Consumer werden neu berechnet
    
    // Eigene Gleichheit: Der Wert ändert sich nicht, wenn er nach deiner Regel „derselbe“ ist
    const sameItems = (x: string[], y: string[]) => x.length === y.length && x.every((v, i) => v === y[i]);
    const stableTags = signal(['a', 'b'], { equal: sameItems });
    stableTags.set(['a', 'b']);     // gleich → Version steigt nicht → nichts passiert downstream
    
    // Auch ein computed hat eine Gleichheit: Ist sein Ergebnis gleich, stoppt die Propagation dort
    const parity = computed(() => (n() % 2 ? 'ungerade' : 'gerade'));   // n: 0 → 2 → 4 … parity bleibt 'gerade'
    LiveEquality-Cutoff, mit Zählern
    n = 0 · Die Zahl ist gerade
    KnotenWertNeuberechnungen
    parity = computed(() => n() % 2 ? 'ungerade' : 'gerade')
    label = computed(() => 'Die Zahl ist ' + parity())
    Signalcount = computed(tags().length)
    signal(...) — Standardgleichheit (Object.is) 2 · neu berechnet ×
    signal(..., { equal: sameItems }) 2 · neu berechnet ×
    Klicke ein paar Mal auf „n + 2“: parity wird neu berechnet (n hat sich geändert), bleibt aber „gerade“, also wird label NICHT mehr neu berechnet. Setze dann dasselbe Array: Mit der Standardgleichheit wird count neu berechnet, mit dem eigenen equal nicht.

    Dynamische Abhängigkeiten

    Bei jedem Durchlauf wird die Liste der Producer eines Consumers aus dem neu aufgebaut, was er tatsächlich gelesen hat. Ein Signal, das nur in einem if-Zweig gelesen wird, ist nur so lange eine Abhängigkeit, wie dieser Zweig läuft. Das ist ein Performance-Gewinn, aber auch eine Quelle der Verwirrung: „Ich ändere details und nichts passiert“ ist meist korrekt, weil der aktuelle Zweig es nicht liest.

    const view = computed(() => {
      if (showDetails()) {
        return details();     // Abhängigkeiten: showDetails + details
      }
      return summary();       // Abhängigkeiten: showDetails + summary
    });
    // Bei jedem Durchlauf wird die Liste der Producer aus dem aufgebaut, was TATSÄCHLICH gelesen wurde.
    // Solange showDetails() false ist, berechnet eine Änderung von details view nicht neu.
    LiveWas ein computed bei jedem Durchlauf liest

    view() = Zusammenfassung v0

    Beim letzten Durchlauf erfasste Abhängigkeiten: · view neu berechnet ×

    Klicke bei showDetails = false auf „details ändern“: view wird nicht neu berechnet, weil es nicht von details abhängt. Schalte showDetails um und wiederhole: Jetzt ist details eine Abhängigkeit und summary nicht mehr.

    Effects und Templates: die Live-Consumer

    Effects laufen asynchron, während der Change Detection, nicht im Moment von set(). Die Dokumentation zu v22 unterscheidet zwei Arten. Ein View-Effect wird im Kontext einer Komponente erstellt: Er läuft, bevor diese Komponente geprüft wird, und wird zusammen mit ihr zerstört. Ein Root-Effect wird in einem Root-Service erstellt: Er läuft, bevor alle Komponenten geprüft werden, und lebt so lange wie die Anwendung. Ändert sich eine Abhängigkeit, während der Effect läuft, läuft er noch einmal, bevor die Change Detection weitermacht.

    // View-Effect: im Kontext einer Komponente erstellt → läuft VOR der Prüfung dieser Komponente
    // durch die Change Detection; er wird zusammen mit der Komponente zerstört.
    @Component({ /* ... */ })
    export class Profile {
      constructor() {
        effect(() => console.log('profil', this.user()));
      }
    }
    
    // Root-Effect: in einem Root-Service erstellt → läuft vor der Prüfung aller Komponenten;
    // er lebt so lange wie die Anwendung.
    @Injectable({ providedIn: 'root' })
    export class Analytics {
      constructor() {
        effect(() => track(this.route()));
      }
    }
    // Beide sind asynchron (sie laufen nicht im Moment von set()) und an die Change Detection gekoppelt.

    Auch das Template einer Komponente ist ein reaktiver Consumer. Ändert sich ein im Template gelesenes Signal, markiert Angular die Komponente zur Prüfung (wie markForCheck), und die Change Detection rendert nur sie und ihre Vorfahren neu. Darauf stützen sich zoneless-Anwendungen und das Standard-OnPush von v22 (siehe Change Detection).

    @Component({
      template: `<p>{{ fullName() }}</p>`,   // das Template ist ein reaktiver Consumer
    })
    export class Card {
      readonly first = signal('Ana');
      readonly fullName = computed(() => `${this.first()} Pop`);
    }
    // first.set('Ioana') → der reaktive Knoten des Templates wird als dirty markiert → die Komponente wird
    // zur Prüfung markiert (wie bei markForCheck) → die Change Detection rendert sie neu. Kein Zone.js,
    // keine Prüfung des ganzen Baums: So funktionieren zoneless-Anwendungen.

    Wann ja, wann nein

    Nutze das Modell zu deinem Vorteil
    • Teure Ableitungen in einem computed: Sie werden nur bei Bedarf und einmal pro Änderung berechnet.
    • Ketten aus mehreren computeds statt eines riesigen computed. Mit Equality-Cutoff stoppen kleine Änderungen früh.
    • { equal } für Werte, die oft neu erzeugt werden, aber „dieselben“ sind (Filter, ID-Listen vom Server).
    • untracked für Lesezugriffe, die nichts auslösen sollen (Logging, Analytics).
    Was der Graph nicht für dich übernimmt
    • Er erkennt keine Mutationen: push auf ein Array in einem Signal benachrichtigt niemanden.
    • Er ordnet deine Seiteneffekte nicht: Brauchst du eine strenge zeitliche Reihenfolge, nimm RxJS (siehe Fortgeschrittenes RxJS).
    • Er ist kein Event-Mechanismus: „Es wurde geklickt“ ist kein Zustand. Nutze output() oder ein Subject.
    • Er führt Effects nicht synchron aus: Brauchst du das Ergebnis sofort, leite es mit computed ab.

    Häufige Stolperfallen

    // ✗ Schreiben innerhalb eines computed — Fehler: "Writing to signals is not allowed in a `computed`"
    const total = computed(() => {
      count.set(items().length);       // Seiteneffekt in einer Ableitung
      return items().reduce(sum, 0);
    });
    
    // ✗ Effect für eine Ableitung missbraucht (ein zusätzliches Rendering, Risiko von Schleifen)
    effect(() => total.set(items().reduce(sum, 0)));
    
    // ✓ Die Ableitung ist ein computed
    const total2 = computed(() => items().reduce(sum, 0));
    
    // ✗ Mutation: gleiche Referenz → Object.is sagt „gleich“ → nichts wird aktualisiert
    items().push(newItem);
    // ✓
    items.update((list) => [...list, newItem]);
    • „Es reagiert nicht“: Prüfe, ob das Signal in dem Zweig gelesen wird, der läuft, und ob du es mit () liest. Eine Referenz auf ein Signal ohne Aufruf erzeugt keine Abhängigkeit.
    • Große Objekte in einem einzigen Signal: Jedes geänderte Feld berechnet alles neu, was vom Objekt abhängt. Teile den Zustand auf oder leite die Felder mit computed ab.
    • Ein Effect, der in andere Signals schreibt: zusätzliche Renderings und das Risiko von Schleifen. Fast immer ist ein computed oder ein linkedSignal die Lösung.
    • Lesezugriffe im Konstruktor, „damit es bereit ist“: Ein zu früh gelesenes computed wird mit unvollständigen Daten berechnet. Lass es lazy.

    Spickzettel

    KNOTEN        ROLLE                   WANN ER LÄUFT
    signal        Producer                — (ändert bei set/update nur Wert und Version)
    computed      Consumer + Producer     lazy: beim Lesen, nur wenn sich eine Abhängigkeit geändert hat
    effect        „Live“-Consumer         asynchron, während der Change Detection (View: vor der Komponente; Root: vor allen)
    template      „Live“-Consumer         wenn die Komponente nach der dirty-Markierung neu gerendert wird
    
    REGELN
      Abhängigkeiten = was du beim letzten Durchlauf TATSÄCHLICH gelesen hast (dynamisch, pro Zweig)
      Standardgleichheit Object.is; { equal } für „gleiche“ Werte → stoppt die Propagation
      ein computed ohne Leser wird gar nicht berechnet
      schreibe keine Signals in einem computed; leite Zustand nicht mit einem effect ab
      untracked(() => …) liest, ohne eine Abhängigkeit zu erzeugen

    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