Am schnellsten lernt man Angular, wenn man etwas Kleines von Anfang bis Ende baut. Auf dieser Seite baust du eine Leseliste: Du beginnst mit einer Komponente, die drei Titel zeigt, und endest mit einer App, die deine Bücher zwischen zwei Besuchen behält. Jeder Schritt bringt eine einzige Idee und verlinkt auf die Seite, die sie ausführlich erklärt.
Im Lab führt die App links den Code rechts aus. Lies den Code, spiel mit der App und geh dann zum nächsten Schritt.
Das Projekt anlegen
Die Angular CLI legt das Projekt an, erzeugt Dateien und startet einen Entwicklungsserver, der die Seite bei jedem Speichern neu lädt. Neue Projekte in v22 nutzen Standalone-Komponenten, Signals und kein Zone.js — genau das, was diese Seite verwendet.
npm install -g @angular/cli
ng new reading-list # Standalone-Komponenten, zoneless und Signals als Standard
cd reading-list
ng generate component reading-list
ng serve # http://localhost:4200In sechs Schritten bauen
Jeder Schritt ist eine echte Komponente. Ändere etwas in der Live-App und such dann im Code die Zeile, die das bewirkt hat.
Eine Komponente ist eine Klasse plus ein Template. Der Zustand ist ein Signal mit drei Büchern, und @for zeichnet für jedes Buch eine Zeile.
Meine Bücher
- Frankenstein
- Dracula
- Moby-Dick
import { Component, signal } from '@angular/core';
interface Book {
id: number;
title: string;
read: boolean;
}
@Component({
selector: 'app-reading-list',
template: `
<h3>Meine Bücher</h3>
<ul>
<!-- track: woran Angular die Zeilen unterscheidet -->
@for (book of books(); track book.id) {
<li>{{ book.title }}</li>
}
</ul>
`,
})
export class ReadingList {
// der Zustand: ein Signal mit einer Liste
protected readonly books = signal<Book[]>([
{ id: 1, title: 'Frankenstein', read: true },
{ id: 2, title: 'Dracula', read: false },
{ id: 3, title: 'Moby-Dick', read: false },
]);
}Was du verwendet hast
| Schritt | Konzepte | Mehr dazu |
|---|---|---|
| 1. Eine Liste zeigen | eine Komponente, signal(), @for mit track | Signals · Control Flow |
| 2. Bücher hinzufügen | [value], (input), (keydown.enter), update() | Data Binding |
| 3. Als gelesen markieren | computed(), @if, @empty | Signals · Control Flow |
| 4. In Komponenten aufteilen | input.required(), output() | input() und output() |
| 5. Den Zustand in einen Service verlegen | @Service(), inject(), asReadonly() | Services |
| 6. Speichern und filtern | effect(), localStorage, ein Filter als computed | effect() · Listen · SSR-sicherer Code |
Vier Bugs, die jeder einmal schreibt
Das sind die Bugs, die in fast jeder ersten Angular-App auftauchen. Schalte sie einzeln ein, sieh dir das Symptom mit eigenen Augen an und lies dann, warum es passiert.
- Frankenstein
- Dracula
- Moby-Dick
Probier: Drücke mit eingeschaltetem Bug auf „Hamlet“ hinzufügen. Die Liste zeigt vier Bücher, aber das computed und die OnPush-Komponente sagen immer noch drei. Zurücksetzen bringt alles auf einmal in Ordnung.
Warum: push() verändert das Array, das das Signal schon hält. Das Signal vergleicht Referenzen, sieht dasselbe Array und benachrichtigt niemanden; die Liste sieht nur richtig aus, weil der Klick diese eine Komponente neu gerendert hat. Gib dem Signal ein neues Array: update((list) => [...list, book]).
// ✗ dasselbe Array, direkt verändert: das Signal sieht dieselbe Referenz und benachrichtigt niemanden
this.books().push(book);
// ✓ ein neues Array: das Signal benachrichtigt alle, die es lesen
this.books.update((list) => [...list, book]);Alle vier haben dieselbe Wurzel: Angular vertraut dem, was du ihm sagst. Ein Signal vertraut darauf, dass ein neuer Wert eine neue Referenz bedeutet, track vertraut deinem Schlüssel, und ein computed vertraut darauf, dass es nur rechnet. Halte diese Versprechen, und das Framework erledigt den Rest.
Wie es weitergeht
- Eine Seite pro Buch, mit eigener URL: Routing.
- Ein echtes Formular mit Validierung zum Hinzufügen von Büchern: Signal Forms.
- Bücher von einem Server laden: HttpClient und resource().
- Tests für den Store und die Komponenten: Testen.
- Wohin die Dateien kommen, wenn die App wächst: Ordnerstruktur.