AngularAtlasAusg. 22.2

Kap. 02Moderne Grundlagen06 / 75

Data Binding & Events

Interpolation, Property- und Attribut-Bindings, Events mit $event und Tastenfiltern und wie [( )] aufgebaut ist — was in das DOM geht und was zurückkommt.

~0 Min. Lesezeit Offizielle Doku

Ein Template ist kein statisches HTML: Angular hält es mit der Klasse der Komponente verbunden. Die Klammern sagen dir, in welche Richtung die Daten fließen — {{ }} und [ ] bringen Werte aus der Klasse ins DOM, ( ) bringt Events zurück in die Klasse, und [( )] macht beides.

Die meisten Anfängerfehler hier sind keine Syntaxfehler. Sie kommen aus drei Fragen: In welche Richtung fließen die Daten, setze ich eine DOM-Property oder ein HTML-Attribut, und welches Element hat den Klick wirklich bekommen?

Warum das wichtig ist
Jeder Bildschirm, den du baust, besteht aus diesen vier Bindings. Wenn du genau weißt, was jedes davon schreibt und wann, sind ein Feld, das sich nicht zurücksetzt, ein Button, der deaktiviert bleibt, oder ein Klick, der das Falsche öffnet, keine Rätsel mehr.

Vier Bindings, zwei Richtungen

Daten gehen mit {{ }} und [ ] nach unten, Events kommen mit ( ) nach oben. Angular wertet die Ausdrücke rechts neu aus, wenn sich die gelesenen Signals ändern, und schreibt ins DOM nur, wenn das Ergebnis anders ist als beim letzten Mal.

SyntaxRichtungWas passiert
{{ expr }}Klasse → DOMsetzt den Text eines Knotens (immer Text, nie HTML)
[prop]="expr"Klasse → DOMsetzt eine Property des DOM-Elements
[attr.x]="expr"Klasse → DOMsetzt oder entfernt ein HTML-Attribut
(event)="stmt"DOM → Klasseführt eine Anweisung aus, wenn das Event eintritt
[(x)]="sig"in beide Richtungenein Property-Binding plus ein Änderungs-Event, in einem
<!-- Klasse → DOM -->
<h2>{{ title() }}</h2>                          <!-- Interpolation: Text -->
<img [src]="avatarUrl()" [alt]="userName()" />  <!-- Property-Binding -->
<td [attr.colspan]="wide() ? 2 : null"></td>    <!-- Attribut-Binding -->

<!-- DOM → Klasse -->
<button (click)="save()">Speichern</button>     <!-- Event-Binding -->

<!-- in beide Richtungen -->
<app-rating [(value)]="stars" />                <!-- Two-Way-Binding -->

Interpolation: immer Text

{{ }} macht aus dem Wert einen String und setzt ihn in einen Textknoten. HTML im Wert erscheint als Zeichen und wird nicht interpretiert — das schützt dich vor XSS. Signals liest man, indem man sie aufruft: {{ count() }}. Halte den Ausdruck billig und ohne Seiteneffekte: Er kann bei jedem Durchlauf der Change Detection laufen.

<!-- der Wert wird Text: '<b>Ana</b>' erscheint mit seinen Klammern, nicht fett -->
<p>Hallo, {{ userName() }}!</p>

<!-- jeder Ausdruck ohne Seiteneffekte; Signals werden aufgerufen -->
<p>{{ items().length }} Artikel · {{ total() | currency: 'EUR' }}</p>
<p>{{ user()?.address?.city ?? 'noch keine Stadt' }}</p>

<!-- ✗ der Text der Signal-Funktion, nicht ihr Wert -->
<p>{{ count }}</p>

Property-Binding setzt eine DOM-Property

[value]="name()" fasst das HTML nicht an. Es setzt die Property value des Input-Elements. Attribute sind die Startwerte im HTML; Properties sind der aktuelle Zustand des Elements. Wenn der Nutzer tippt, ändert sich die Property, das Attribut bleibt, wie es war. Und Angular schreibt die Property nur, wenn sich name() ändert — hält die Klasse noch denselben Wert, ändert ein Zurücksetzen nichts an dem, was der Nutzer getippt hat.

@Component({
  selector: 'app-profile',
  template: `
    <!-- setzt input.value; ändert das Attribut value="" nicht -->
    <input [value]="name()" (input)="name.set(box.value)" #box />
    <button [disabled]="saving()" (click)="save()">Speichern</button>
    <button (click)="reset()">Zurücksetzen</button>
  `,
})
export class Profile {
  readonly name = signal('Ana');
  readonly saving = signal(false);

  reset() {
    // funktioniert nur, weil (input) name() aktuell hält;
    // mit [value] allein ist name() noch 'Ana', und set('Ana') ändert nichts
    this.name.set('Ana');
  }
}
LiveProperty oder Attribut, und ein Reset, der nicht zurücksetzt
name()in der Klasse'Ana'
input.valueDOM-Property'Ana'
getAttribute('value')HTML-Attributnull

synchronFeld und Signal sagen beide 'Ana'.

Statisches Attribut oder Property-Binding
Klicks: 0

Der erste Button ist deaktiviert: Das Attribut existiert, und sein Textwert spielt keine Rolle.

Im Modus [value]: Tippe einen Nachnamen hinter „Ana“ und drücke dann name.set('Ana'). Wiederhole das im zweiten Modus und vergleiche die Tabelle und die beiden Buttons darunter.

Im ersten Modus zeigt das Feld Text, von dem die Klasse nichts weiß. name.set('Ana') gibt dem Signal den Wert, den es schon hatte; also ändert sich nichts, und Angular schreibt nicht ins Input. Liest du das Input mit (input) zurück — oder bindest du in beide Richtungen mit [( )] oder einem Formular —, bleiben Klasse und DOM im Gleichschritt. Beachte, dass getAttribute('value') die ganze Zeit null bleibt: Angular hat das Attribut nie gesetzt.

Wenn es keine Property gibt: [attr.]

Manche Attribute haben keine passende Property: aria-*, colspan, data-*, Attribute an SVG. Dafür nimmst du [attr.name]. Ein Wert null oder undefined entfernt das Attribut — so schaltest du aria-current ein und aus. Klassen und Styles haben eigene Bindings, erklärt unter [class] und [style].

Boolesche Attribute sind die klassische Falle: Der Browser schaut nur, ob das Attribut existiert. disabled="false" ist ein String, das Attribut ist da, und der Button ist deaktiviert. [disabled]="false" setzt die Property auf den Boolean false.

<!-- dafür gibt es keine DOM-Property: das Attribut binden -->
<td [attr.colspan]="span()">…</td>
<svg><circle [attr.r]="radius()" /></svg>
<div [attr.data-state]="state()"></div>

<!-- null entfernt das Attribut: aria-current gibt es nur am aktiven Link -->
<a [attr.aria-current]="active() ? 'page' : null" href="/orders">Bestellungen</a>

<!-- ✗ das Attribut existiert, also ist der Button deaktiviert -->
<button disabled="false">Speichern</button>
<!-- ✓ die Property bekommt den Boolean false -->
<button [disabled]="false">Speichern</button>

Event-Binding: ( )

(click)="save()" hängt einen Listener an das Element und führt die Anweisung aus, wenn das Event eintritt. $event ist das DOM-Event-Objekt: ein MouseEvent bei Klicks, ein KeyboardEvent bei Tasten oder der ausgegebene Wert beim output() einer Komponente. Um ein Feld zu lesen, ist eine Template-Referenz wie #box einfacher und vollständig typisiert: (input)="name.set(box.value)".

<button (click)="save()">Speichern</button>

<!-- $event ist das DOM-Event; bei einem output() der ausgegebene Wert -->
<div (pointermove)="track($event.clientX, $event.clientY)"></div>
<app-rating (valueChange)="stars.set($event)" />

<!-- eine Template-Referenz ist als HTMLInputElement typisiert: keine Casts -->
<input #box (input)="query.set(box.value)" />

<!-- ✗ im Strict Mode: 'value' does not exist on type 'EventTarget' -->
<input (input)="query.set($event.target.value)" />

Events steigen auf (Bubbling)

Ein Klick beginnt beim innersten Element und wandert dann durch jeden Vorfahren nach oben, wobei auch deren (click)-Handler laufen. So öffnet ein Löschen-Button in einer klickbaren Zeile auch die Zeile — der Handler der Zeile läuft direkt nach dem des Buttons.

LiveEin Löschen-Button in einer klickbaren Zeile
  • Bestellung #1042
  • Bestellung #1043
  • Bestellung #1044
Handler, die gelaufen sind, in Reihenfolge

Noch nichts geklickt.

Drücke bei einer Bestellung auf Löschen und schau auf Details und die Liste der Handler. Wechsle dann zu $event.stopPropagation() und versuch es noch einmal.

$event.target ist das Element, auf dem der Klick begonnen hat, und in jedem Handler dasselbe. $event.currentTarget ist das Element, dessen Handler gerade läuft. stopPropagation() im inneren Handler ist die schnelle Lösung. Besser ist oft, gar nicht zu verschachteln: Die Aktion der Zeile wird ein echter Link oder Button neben Löschen, kein Klick-Handler auf der ganzen Zeile — dann können sie auch Tastaturnutzer öffnen.

<ul>
  @for (order of orders(); track order.id) {
    <!-- die Zeile öffnet die Bestellung… -->
    <li (click)="open(order)">
      Bestellung #{{ order.id }}
      <!-- …und ohne stopPropagation() erreicht ein Klick hier auch die Zeile -->
      <button (click)="remove(order); $event.stopPropagation()">Löschen</button>
    </li>
  }
</ul>

<!-- oft besser: zwei getrennte Aktionen, keine Verschachtelung, per Tastatur erreichbar -->
<li>
  <a [routerLink]="['/orders', order.id]">Bestellung #{{ order.id }}</a>
  <button (click)="remove(order)">Löschen</button>
</li>

Tastenfilter und die Standardaktion des Browsers

Angular lässt dich Tastatur-Events direkt im Binding filtern: (keydown.enter), (keydown.escape), (keydown.shift.enter), (keydown.control.s). Die Modifier müssen genau passen: (keydown.enter) feuert nicht bei Shift+Enter. Dein Handler läuft vor der Standardaktion des Browsers — einen Zeilenumbruch einfügen, das Formular absenden, einem Link folgen —, und $event.preventDefault() bricht diese Aktion ab.

<textarea
  #msg
  [value]="draft()"
  (input)="draft.set(msg.value)"
  (keydown.enter)="send($event)"
  (keydown.escape)="draft.set('')"
></textarea>
<!-- (keydown.enter) feuert nicht bei Shift+Enter: der Browser fügt wie gewohnt eine Zeile ein -->
LiveEin Chatfeld: Enter sendet, Shift+Enter fügt eine Zeile hinzu
  • Noch keine Nachrichten.
(keydown)—
(keydown.enter)—
(keydown.shift.enter)—
(keydown.escape)—

Drück eine Taste im Nachrichtenfeld.

Schreib eine Nachricht und drücke in jedem Modus Enter. Probier dann Shift+Enter und Escape und beobachte, welche Bindings laufen.

Ohne preventDefault() fügt der Browser den Zeilenumbruch ein, nachdem dein Handler draft geleert hat, und das (input)-Event schreibt den Text zurück. Noch ein Detail, das die meisten Chatfelder falsch machen: Solange jemand Japanisch oder Chinesisch mit einer Eingabemethode (IME) tippt, bestätigt Enter die Zeichen. Prüfe $event.isComposing und ignoriere die Taste in diesem Fall.

[( )] ist [ ] plus ( )

Die „Banane in der Box“ ist eine Abkürzung. [(value)]="name" bedeutet ein Property-Binding auf value plus einen Listener für das Event valueChange, der zurückschreibt. Übergibst du ein WritableSignal, setzt Angular das Signal für dich. In deinen eigenen Komponenten erzeugt model() beide Hälften; für Formularfelder nimm Signal Forms.

<!-- die Kurzform… -->
<app-rating [(value)]="stars" />

<!-- …bedeutet genau das -->
<app-rating [value]="stars()" (valueChange)="stars.set($event)" />

<!-- mit einem WritableSignal ruft Angular set() für dich auf;
     das Kind deklariert es mit: value = model(0) -->

Template-Referenzvariablen

#name an einem Element gibt dir das Element im restlichen Template; an einer Komponente die Instanz der Komponente. Das ist der schnellste Weg, ein Feld zu lesen oder focus() aufzurufen, ohne über $event.target zu gehen, dessen Typ nur EventTarget ist. In der Klasse erreichst du dieselbe Referenz mit viewChild().

<!-- an einem Element: das Element selbst -->
<input #search placeholder="Suchen" />
<button (click)="search.focus()">Fokus</button>

<!-- an einer Komponente: die Instanz der Komponente -->
<app-video-player #player />
<button (click)="player.play()">Abspielen</button>

<!-- in der Klasse: readonly search = viewChild<ElementRef<HTMLInputElement>>('search') -->

Gute Gewohnheiten / vermeiden

Gute Gewohnheiten
  • Die Quelle der Wahrheit in der Klasse halten (ein Signal) und jede Änderung aus dem DOM zurücklesen.
  • Template-Referenzen (#box) statt $event.target verwenden, wenn du einen Wert brauchst.
  • [attr.] für aria-* und data-* nutzen und null, um ein Attribut zu entfernen.
Vermeiden
  • Funktionen mit viel Arbeit in {{ }} oder [ ] — sie laufen bei jedem Durchlauf erneut.
  • Statische boolesche Attribute mit Wert (disabled="false"): Es zählt nur, dass das Attribut da ist.
  • stopPropagation() aus Gewohnheit: Es versteckt das Event auch vor Analytics, vor Menüs, die sich bei einem Klick außerhalb schließen, und vor deinen Kollegen.

Häufige Stolperfallen

  • Ein Reset, der nicht zurücksetzt. Das Feld war nur in eine Richtung gebunden, der Nutzer hat getippt, und die Klasse hält noch den alten Wert. Ihn erneut zu setzen, ändert nichts.
  • Vergessene Klammern. {{ count }} gibt die Signal-Funktion selbst aus, nicht ihren Wert. Der Compiler warnt davor; ignoriere die Warnung nicht.
  • Die Zeile öffnet sich beim Klick auf Löschen. Der Klick ist vom Button zur Zeile aufgestiegen. Stoppe ihn oder verschachtle keine Aktionen.
  • Ein Zeilenumbruch bleibt nach dem Senden stehen. Die Standardaktion von Enter lief nach dem Handler. Ruf $event.preventDefault() auf.
  • $event.target.value schreiben. target ist ein EventTarget, im Strict Mode kompiliert das nicht. Nimm eine Template-Referenz oder lies es in der Klasse mit einem Cast.

Spickzettel

{{ expr }}             Text ins DOM; HTML wird escapt; Signals aufrufen: {{ count() }}
[prop]="expr"          eine DOM-Property (value, disabled, src, checked) oder ein Komponenten-Input
[attr.x]="expr"        ein HTML-Attribut (aria-*, data-*, colspan, svg); null entfernt es
[class.x] / [style.x]  eine Klasse oder ein Style; siehe die Seite [class] und [style]
(event)="stmt"         ein Listener; $event = das DOM-Event oder der ausgegebene Wert
(keydown.enter)        Tastenfilter; Modifier müssen passen: shift.enter, control.s, escape
[(x)]="sig"            [x]="sig()" + (xChange)="sig.set($event)"
#ref                   das Element oder die Komponenteninstanz, im Template

wann geschrieben wird  nur wenn der Wert anders ist als der zuletzt geschriebene
Attribut vs. Property  Attribut = Startwert im HTML; Property = aktueller Zustand
Bubbling               ein Klick führt die Handler aller Vorfahren aus; target bleibt gleich
Standardaktionen       laufen nach deinem Handler; $event.preventDefault() bricht sie ab

Kap. 02 · 0 von 8 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. Standalone & Bootstrap
  2. Data Binding & Events
  3. Control Flow: @if, @for, @switch
  4. @let und die neuen Template-Ausdrücke
  5. @defer — Lazy Loading in Templates
  6. Class- & Style-Bindings
  7. Komponenten-Styles & Kapselung
  8. Pipes: wann und wie
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