Angular ist ein TypeScript-basiertes Front-End-Webapplikationsframework. Es wird von einer Community aus Einzelpersonen und Unternehmen, angeführt durch Google, entwickelt und als Open-Source-Software publiziert.
Wikipedia (18.08.2024)
Hier geht es zur offiziellen Angular-Dokumentation.
Um eine Angular-Anwendung programmieren und ausführen zu können, benötigst du:
Nachdem du sichergestellt hast, dass du alle diese Komponenten installiert hast, musst du über den Node-Package-Manager (kurz npm) noch die Angular-Kommandozeilentools (Angular CLI) installieren. Damit kannst du im nächsten Schritt z.B. ein neues Projekt automatisch anlegen.
Öffne dazu das Terminal und führe den folgenden Befehl aus:
npm install -g @angular/cli
Nun kannst du mit der Angular-Entwicklung beginnen!
Um ein neues Angular-Projekt anzulegen, führe folgenden Befehl innerhalb des Ordners aus, in dem du das Projekt speichern möchtest:
ng new MeineErsteApp
Schauen wir uns diesen Befehl einmal genauer an: ng steht für "Angular" (bzw. genauer das Angular CLI). Mit new geben wir an, dass wir ein neues Projekt anlegen wollen. Danach folgt der Name für unser Projekt, in diesem Fall soll es MeineErsteApp heißen.
Der Befehl
ng newist nur einer von vielen Angular-CLI-Befehlen. Wir werden später weitere solcher Befehle kennenlernen.
Wenn du den Befehl ausführst, werden dir verschiedene Auswahl-Menüs angezeigt. Darin kannst du mit den Pfeiltasten eine Option auswählen und sie mit Enter bestätigen. Ggf. muss du auch eine Frage mit Ja (Y) oder Nein (N) beantworten.
Die gestellten Fragen sowie die Auswahlmöglichkeiten können sich je nach Angular-Version ändern. Hier wurde das Angular CLI 20.1.3 verwendet.
Werden wir nach dem Stylesheet-Format gefragt, wählen wir die Option Sass (SCSS) (mehr dazu später). Bei allen anderen Optionen können wir die Standard-Option auswählen.
Bei einer Auswahl auf der Kommandozeile gibt es oft eine Standard-Option. Bei Ja-/Nein-Fragen ist diese meistens am Großbuchstaben erkennbar:
y/N→ "Nein" ist die Standard-Option. Die Standard-Option kann auch durch direktes Drücken der Enter-Taste ausgewählt werden.
Haben wir alle Fragen beantwortet, wird unsere Anwendung erstellt (das kann einen Moment dauern). Anschließend können wir die Web-App testen. Dazu navigieren wir zuerst in den Ordner, der für die Anwendung angelegt wurde:
cd MeineErsteApp
Anschließend können wir die Anwendung auch schon ausführen:
ng serve
Nun wird ein lokaler Webserver gestartet, der die Anwendung zur Verfügung stellt. Diese können wir über unseren Browser aufrufen, indem wir die URL http://localhost:4200/ in die Adresszeile eingeben.
Für die CLI-Befehle gibt es auch Kurzschreibweisen. Statt
ng servekönnen wir beispielsweise auch nurng sschreiben.
Wie wir sehen, wurde für unsere Anwendung schon ein beispielhafter Inhalt angelegt, der auf die Angular-Dokumentation verlinkt. Somit können wir sehen, dass unsere Anwendung erfolgreich erstellt wurde und funktioniert. Den Inhalt passen wir in den nächsten Schritten an.

Nachdem wir nun unsere erste App angelegt haben, schauen wir uns einmal die erstellten Dateien genauer an. Dazu öffnen wir zunächst unseren Projekt-Ordner in Visual Studio Code. Das geht über die Funktion Datei > Ordner öffnen... in VS Code oder direkt über die Kommandozeile:
code .
Wie wir sehen, wurden beim Erstellen des Projektes gleich eine ganze Menge an Dateien angelegt:

Zunächst gibt es ein paar Dateien, die für die Konfiguration unserer Angular-App benötigt werden und mit denen wir erst einmal nichts bzw. wenig zu tun haben:
index.html |
Hauptseite der Webanwendung. Den Inhalt dieser Seite verändern wir allerdings nicht, dafür verwenden wir Komponenten (mehr dazu später). |
main.ts |
Hauptprogramm für die Anwendungslogik. Auch hier müssen wir nichts verändern. |
styles.scss |
Haupt-Stylesheet. Hier können wir bei Bedarf globale Styles festlegen. |
angular.json |
Projekt-Konfiguration. Hier können wir z.B. Build-Skripte anlegen (brauchen wir erst einmal nicht). |
package[-lock].json |
Hier werden Abhängigkeiten angegeben, z.B. wenn wir eine externe Bibliothek nutzen möchten. Diese werden automatisch von Angular angelegt. |
tsconfig.[...].json |
Konfiguration des Typescript-Compilers. |
Kommen wir nun aber zum ineressanten Teil, nämlich den Dateien, in denen wir tatsächlich unseren Code schreiben. Im Ordner /src/app finden wir zu Beginn sechs Dateien. Zwei davon werden für übergreifende Konfigurationen werwendet:
app.config.ts |
Hier können wir bestimmte Konfigurationen für unsere Web-Anwendung vornehmen. |
app.routes.ts |
Hier können wir sogenannte Routen festlegen, diese werden zur Navigation innerhalb unserer Anwendung benötigt (mehr dazu später) |
Die restlichen vier Dateien gehören alle zur Hauptseite unserer Anwendung. Bei dieser handelt es sich um eine sogenannte Komponente.
Jede Angular-Anwendung besteht aus einer oder mehreren Komponenten. Damit lassen sich Seiten aus einzelnen, wiederverwendbaren Elementen übersichtlich aufbauen. Möchten wir z.B. eine Anwendung für News-Artikel programmieren, so können wir einmal eine Komponente für einen Artikel erstellen und diese dann mehrfach auf unserer Übersichtsseite einbinden. Durch die Verwendung von Komponenten sparen wir uns viel Programmieraufwand und machen den Code unserer Anwendung übersichtlicher.
Eine Komponente besteht immer aus den folgenden vier Dateien (wie auch unsere Hauptkomponente app):
<name>.html |
Definiert die Struktur der Komponente. |
<name>.scss |
Definiert das Aussehen der Komponente. |
<name>.ts |
Definiert die Logik der Komponente. |
<name>.spec.ts |
Enthält automatisierte Tests für die Komponentenlogik (benötigen wir vorerst nicht). |
Die vielen Dateien, die zu Beginn angelegt werden, können auf den ersten Blick verwirrend wirken. Lass dich davon nicht abschrecken - anfangs musst du dich eigentlich nur auf die drei Dateien der Hauptkomponente konzentrieren, also
app.html,app.scssundapp.ts. Diese stellen genau den Aufbau dar, wie wir ihn von klassichen Webseiten kennen - nämlich die Trennung in Struktur, Aussehen und Logik. Für jede weitere Komponente, die wir anlegen, wiederholt sich dieses Muster einfach nur.
Um ein besseres Gefühl für die Funktionsweise einer Komponente zu bekommen, können wir zunächst einmal den Inhalt der Datei app.html löschen (dieser beinhaltet die Beispielseite, die wir oben gesehen haben). Anschließend können wir unseren eigenen Code einfügen:
<h1>Meine erste App</h1>
<p>Hallo, das ist meine erste Angular-App!</p>
Die Seite im Browser sollte sich nun automatisch aktualisieren und wir sollten unseren neuen Inhalt sehen, nämlich eine große Überschrift "Meine erste App" und darunter einen Textabsatz mit dem Begrüßungstext.
Das Aussehen der Seite können wir nun in der Datei app.scss beeinflussen. Möchten wir z.B. unserer h1-Überschrift eine Hintergrund hinzufügen, können wir das wie folgt tun:
h1 {
background-color: lightblue;
padding: 10px;
}
Über das Attribut background-color ändern wir die Hintergrundfarbe des h1-Tags auf hellblau und über padding geben wir die Breite des Rands an, der um den Text herum eingefügt werden soll.
Die Seite sollte nun wie folgt aussehen:

Jetzt fehlt nur noch die Datei app.ts. Hier können wir Logik für unsere Anwendung programmieren, um zum Beispiel festzulegen, was passiert, wenn wir auf einen Button klicken. Möchten wir z.B. einen solchen Button hinzufügen, müssen wir ihn zuerst im HTML unserer App anlegen. Dafür fügen wir folgendes hinzu:
<button>Klick mich!</button>
Jetzt sollten wir unserhalb unseres Textes einen Button mit der Aufschrift "Klick mich!" sehen. Wenn wir darauf klicken, passiert allerdings noch nichts. Das liegt daran, dass wir noch nirgends definiert haben was beim Klicken passieren soll. Genau dafür ist nun unsere TypeScript-Datei da: Hier legen wir als nächstes innerhalb der App-Klasse eine Funktion an und nennen diese onButtonClicked() (den Namen können wir natürlich frei wählen):
export class App {
onButtonClicked(){
alert("Hallo, ich bin ein Button!");
}
}
Der Befehl alert sorgt dabei dafür, dass im Browser ein Pop-Up mit einem Text angezeigt wird. Nun müssen wir nur noch festlegen, dass diese Funktion beim Klicken auf den Button aufgerufen wird. Dazu passen wir das HTML wie folgt an:
<button (click)="onButtonClicked()">Klick mich!</button>
Wenn wir nun auf den Button klicken, sollten wir das Pop-Up in unserem Browser sehen.
Was wir hier mit
(click)=...gesehen haben, ist ein sogenanntes Binding. Damit können Daten zwischen dem HTML-Template und dem TypeScript-Code ausgetauscht werden. Weitere Arten von Bindings werden wir später kennenlernen, wenn wir unsere erste richtige App programmieren.
Nun kennen wir den grundlegenden Aufbau einer Angular-Anwendung und können im nächsten Schritt damit beginnen, unsere erste richtige Anwendung zu programmieren.
Als Beispiel wollen wir hier eine einfach ToDo-Listen-App entwickeln. Sie soll folgende Funktionen haben:
So soll die Anwendung aussehen, wenn sie fertig ist:

Diese wollen wir nun Schritt für Schritt aufbauen. Dazu gehen wir wie folgt vor:
Die einzelnen Schritte werden in den folgenden Abschnitten erklärt.
Für unsere App müssen wir zuerst wieder ein neues Angular-Projekt anlegen. Dafür nutzen wir wieder den oben gezeigten Befehl:
ng new TodoApp
Als Stylesheet-Format wählen wir auch hier wieder Sass (SCSS) und bei allen anderen Abfragen wählen wir die Standard-Option. Anschließend können wir das Projekt wieder in VS Code öffnen und die App mit dem folgenden Befehl ausführen:
ng serve
Wenn alles geklappt hat, sollten wir auch hier wieder eine Beispiel-Seite angezeigt bekommen.
Kümmern wir uns zunächst um den grundlegenden Aufbau unserer App. Alles, was wir hier sehen, hat noch nichts direkt mit Angular zu tun und könnte auch so mit HTML und CSS umgesetzt werden.
Zunächst wechseln wir in die Datei app.html und löschen dort den vorgefertigten Inhalt. Nun können wir mit dem Aufbau unserer eigenen HTML-Struktur beginnen.
Als erstes erstellen wir einen Abschnitt (in HTML <div>), der den äußeren Rahmen für unsere App bilden soll. Um sein Aussehen später über CSS anpassen zu können, geben wir ihm die CSS-Klasse main-container. Außerdem soll er die Überschrift unserer App enthalten (h1-Tag):
<div class="main-container">
<h1>Meine Aufgaben</h1>
</div>
Unsere App soll mehrere ToDo-Elemente untereinander anzeigen können. Dafür definieren wir den Aufbau eines solchen Elements. Es wird unterhalb unserer Überschrift eingefügt und bekommt die CSS-Klasse card, ebenfalls für das spätere Styling. Es enthält eine h2-Überschrift für den Titel der Aufgabe, einen Textabschnitt (p-Tag) für die Aufgabenbeschreibung und einen Button, über den die Aufgabe später als erledigt markiert werden kann:
<div class="card">
<h2>ToDo 1</h2>
<p>Beschreibung 1</p>
<button>✔️ Erledigt</button>
</div>
Dieses Element können wir direkt mehrere Male untereinander anordnen.
Zuletzt brauchen wir noch eine Möglichkeit, um neue Aufgaben zu unserer Liste hinzuzufügen. Dafür fügen wir einen weiteren Abschnitt oberhalb unserer Aufgabenliste ein. Dieser enthält ein Formular mit zwei Eingabefeldern für den Titel und die Beschreibung sowie einen Button zum Hinzufügen der Aufgabe:
<div class="card">
<input type="text" placeholder="Titel" class="input-title"/>
<input type="text" placeholder="Beschreibung" class="input-description"/>
<button>➕ Hinzufügen</button>
</div>
Auch hier geben wir direkt die CSS-Klassen an (add-todo, ìnput-title und input-description), die wir im nächsten Schritt für das Styling der Elemente benötigen.
Der gesamte HTML-Code sollte nun wie folgt aussehen:
<div class="main-container">
<h1>Meine Aufgaben</h1>
<div class="card">
<input type="text" placeholder="Titel" class="input-title"/>
<input type="text" placeholder="Beschreibung" class="input-description"/>
<button>➕ Hinzufügen</button>
</div>
<div class="card">
<h2>ToDo 1</h2>
<p>Beschreibung 1</p>
<button>✔️ Erledigt</button>
</div>
<div class="card">
<h2>ToDo 2</h2>
<p>Beschreibung 2</p>
<button>✔️ Erledigt</button>
</div>
<div class="card">
<h2>ToDo 3</h2>
<p>Beschreibung 3</p>
<button>✔️ Erledigt</button>
</div>
</div>
Damit haben wir bereits den gesamten Aufbau unserer App definiert. Allerdings sieht sie noch nicht sehr schön aus. Das liegt daran, das wir das Aussehen noch nicht über CSS definiert haben. Wie das geht, schauen wir uns im nächsten Schritt an.
Für das Styling wechseln wir in die Datei app.scss und löschen dort ggf. den vorgefertigten Inhalt, falls vorhanden. Nun können wir unsere eigenen Style-Definitionen anlegen.
Beginnen wir mit etwas allgemeinem Styling, das unsere gesamte Anwendung betreffen soll. Das können wir mit dem Selektor :host tun:
:host {
font-family: Arial, Helvetica, sans-serif;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
}
Hier definieren wir die Schriftart und -farbe sowie die Anordnung der Elemente auf unserer Seite. Diese sollen alle mittig (center) untereinander (column) angeordnet werden.
Als nächstes definieren wir das Aussehen der Überschriften und des Fließtexts:
/* Überschriften */
h1 {
margin: 0px;
font-size: 24pt;
font-weight: bold;
}
h2 {
margin: 0px;
font-size: 16pt;
font-weight: bold;
}
/* Fließtext */
p {
font-size: 12pt;
}
Hier geben wir die Schriftgröße an und entfernen den Rand (margin), der standardmäßig um die Überschriften herum angezeigt wird.
Anschließend definieren wir das Aussehen unseres Haupt-Containers. Er soll 60% der Seitenbreite einnehmen, einen inneren Abstand (padding) von 20 Pixeln besitzen und einen leicht hellgrauen Hintergrund mit einem leichten Schatten haben:
.main-container {
display: flex;
flex-direction: column;
align-items: center;
width: 60vw;
padding: 20px;
background-color: #FCFCFC;
border-radius: 10px;
box-shadow: #AAAAAA 1px 1px 5px;
}
Ähnliches gilt für die Cards, die für unsere ToDo-Einträge sowie später für das Eingabe-Formular verwendet werden. Sie sollen 40% der Breite unseres Haupt-Containers einnehmen und ebenfalls einen leichten Schatten haben:
.card {
width: 40%;
padding: 15px;
margin: 10px 0px 10px 0px;
background-color: #FCFCFC;
border-radius: 10px;
box-shadow: #AAAAAA 1px 1px 5px;
}
Die Buttons zum Abhaken der Augabe werden ebenfalls gestylt. Hier wird zusätzlich eine andere Hintergrundfarbe für das Hovern über den Button mit dem Mauszeiger (:hover) sowie während des Klickens (:active) definiert:
button {
padding: 10px;
background-color: #EEEEEE;
border: none;
border-radius: 20px;
}
button:hover {
background-color: #CCCCCC;
cursor: pointer;
}
button:active {
background-color: #AAAAAA;
}
Als letztes definieren wir noch das Aussehen der Eingabe-Felder für neue Aufgaben:
input {
width: 100%;
padding: 2px;
background-color: transparent;
border: none;
border-bottom: 1px solid #AAAAAA;
outline: none;
}
.input-title {
margin: 0px 0px 10px 0px;
font-size: 16pt;
font-weight: bold;
}
.input-description {
margin: 10px 0px 20px 0px;
font-size: 12pt;
}
Die gesamte SCSS-Datei sollte letztendlich wie folgt aussehen:
/*
* Allgemeines Styling
*/
/* Seite allgemein */
:host {
font-family: Arial, Helvetica, sans-serif;
color: #333333;
display: flex;
flex-direction: column;
align-items: center;
}
/* Überschriften */
h1 {
margin: 0px;
font-size: 24pt;
font-weight: bold;
}
h2 {
margin: 0px;
font-size: 16pt;
font-weight: bold;
}
/* Fließtext */
p {
font-size: 12pt;
}
/*
* Haupt-Container
*/
.main-container {
display: flex;
flex-direction: column;
align-items: center;
width: 60vw;
padding: 20px;
background-color: #FCFCFC;
border-radius: 10px;
box-shadow: #AAAAAA 1px 1px 5px;
}
/*
* Cards
*/
.card {
width: 40%;
padding: 15px;
margin: 10px 0px 10px 0px;
background-color: #FCFCFC;
border-radius: 10px;
box-shadow: #AAAAAA 1px 1px 5px;
}
/*
* Buttons
*/
button {
padding: 10px;
background-color: #EEEEEE;
border: none;
border-radius: 20px;
}
button:hover {
background-color: #CCCCCC;
cursor: pointer;
}
button:active {
background-color: #AAAAAA;
}
/*
* Eingabefelder
*/
input {
width: 100%;
padding: 2px;
background-color: transparent;
border: none;
border-bottom: 1px solid #AAAAAA;
outline: none;
}
.input-title {
margin: 0px 0px 10px 0px;
font-size: 16pt;
font-weight: bold;
}
.input-description {
margin: 10px 0px 20px 0px;
font-size: 12pt;
}
Nun haben wir das Styling abgeschlossen und unsere App sollte folgendermaßen aussehen:

Natürlich haben wir bisher nur eine fest definierte Liste von Aufgaben und können diese weder abhaken noch neue Aufgaben hinzufügen. Darum kümmern wir uns in den nächsten Abschnitten.
Bisher haben wir die ToDo-Elemente in unserer App direkt als div-Blöcke hinzugefügt, die jeweils einen Text und einen Button enthalten. Wie du dir vielleicht schon denken kannst, haben wir auf diese Weise keine Möglichkeit, dynamisch neue Elemente hinzuzufügen oder bestehende zu löschen – unsere App würde immer genau die drei Elemente anzeigen, die wir oben erstellt haben.
Zum Glück bietet Angular für dieses Problem eine Lösung: die sogenannten Komponenten. Mit einer Komponente ist es möglich, einen Teil unseres HTML-Codes wiederverwendbar zu machen und dabei auch noch bestimmte Werte flexibel zu setzen – beispielsweise sollen ja nicht alle ToDo-Elemente den gleichen Titel und die gleiche Beschreibung haben, aber dennoch den gleichen Aufbau.
In den nächsten Schritten wollen wir nun solch eine Komponente für unsere ToDo-Einträge anlegen und diese in unsere App einbinden.
Wie oben beschrieben besteht eine Komponente immer aus vier Dateien für das HTML, (S)CSS, TypeScript und die Tests (letzere können wir vorerst ignorieren). Diese Dateien müssen wir glücklicherweise nicht für jede Komponente von Hand anlegen – dafür gibt es den Befehl ng generate component <Name>. In diesem Fall geben wir also ein:
ng generate component todo-item
Auch für diesen Befehl gibt es eine Kurzform, nämlich
ng g c <Name>.
Wir sollten nun einen Unterordner mit dem Namen todo-item und die darin enthaltenen vier Dateien sehen:

Nun können wir unsere neu angelegte Komponente in die App einbinden. Dazu müssen wir sie zuerst im TypeScript-Code importieren. Das geht über den import-Befehl ganz am Anfang unseres Dokuments (app.ts):
import { TodoItem } from './todo-item/todo-item';
Zusätzlich müssen wir die Komponente noch zum imports-Array hinzufügen:
imports: [TodoItem]
Die ganze app.ts-Datei sollte nun wie folgt aussehen:
import { Component, signal } from '@angular/core';
import { TodoItem } from './todo-item/todo-item';
@Component({
selector: 'app-root',
imports: [TodoItem],
templateUrl: './app.html',
styleUrl: './app.scss'
})
export class App {
protected readonly title = signal('TodoApp');
}
Den Import
RouterOutlet, der standardmäßig von Angular angelegt wurde, können wir hier einfach löschen. Routing wird für das Wechseln zwischen meheren Unterseiten einer Anwendung benötigt – das brauchen wir für unsere App vorerst nicht.
Nun können wir die Komponente auch schon im HTML userer App (app.html) verwenden. Dazu fügen wir nun einfach den Selektor unserer Komponente an einer beliebigen Stelle ein, in diesem Fall app-todo-item:
<app-todo-item></app-todo-item>
Starten wir unsere Anwendung nun (falls sie nicht mehr läuft) erneut mit ng serve, sollten wir an der entsprechenden Stelle den Text todo-item works! sehen. Dieser kommt daher, dass das HTML der Komponente (in diesem Fall todo-item.html) an dieser Stelle einfach "eingesetzt" wird und die Komponente standardmäßig ein p-Tag mit dem Text <komponenten-name> works! beinhaltet:
<p>todo-item works!</p>
Damit können wir die korrekte Funktionsweise unserer Komponente überprüfen. Natürlich fehlt nun noch der eigentliche Inhalt der Komponente – darum kümmern wir uns im nächsten Schritt.
In diesem Schritt wollen wir unsere Komponente mit Inhalt füllen – schließlich sieht sie noch nicht aus wie unsere ToDo-Items. Dazu gehen wir zunächst in die Datei todo-item.html und löschen dort den Beispiel-Text. Stattdessen fügen wir den HTML-Code für unser ToDo-Item ein:
<h2>ToDo 1</h2>
<p>Beschreibung 1</p>
<button>✔️ Erledigt</button>
Nun fügen wir in der Datei todo-item.scss noch das Styling für unsere Komponente hinzu:
@import url('../app.scss');
:host {
width: 40%;
padding: 15px;
margin: 10px 0px 10px 0px;
background-color: #FCFCFC;
border-radius: 10px;
box-shadow: #AAAAAA 1px 1px 5px;
display: flex;
flex-direction: column;
align-items: baseline;
}
Über @import url('../app.scss') importieren wir zunächste alle Styles aus unserem Haupt-Stylesheet und ergänzen diese dann über den :host-Selektor mit den spezifischen Styles für unsere Komponente. Die entsprechenden Styles aus dem Haupt-Stylesheet können wir löschen (mehr dazu später).
Auch die bisher manuell erstellen ToDo-Elemente in app.html können wir nun entfernen:
<div class="main-container">
<h1>Meine Aufgaben</h1>
<div class="card">
<input type="text" placeholder="Titel" class="input-title"/>
<input type="text" placeholder="Beschreibung" class="input-description"/>
<button>➕ Hinzufügen</button>
</div>
<app-todo-item></app-todo-item>
<app-todo-item></app-todo-item>
<app-todo-item></app-todo-item>
</div>
Das ToDo-Element können wir direkt mehrmals untereinander einfügen. Nun sollten wir wieder drei ToDo-Elemente sehen, die gleich aussehen wie zuvor, nun aber über unsere Komponente geladen werden.
Obwohl wir den ToDo-Eintrag nun in eine eigene Komponente ausgelagert haben, hat dieser noch immer feste Werte (Titel, Beschreibung), die nun auch noch für jeden Eintrag gleich sind, da wir sie fest in der Komponente angegeben haben. Stattdessen brauchen wir eine Möglichkeit, diese Eigenschaften für jede Instanz der Komponente dynamisch festlegen zu können.
Dafür bietet Angular die sogenannten Input-Bindings an, mit denen man Werte an eine Komponente übergeben kann.
Analog dazu gibt es auch
Output-Bindings, über die die Komponente Daten zurück an die Anwendung geben kann. Diese benötigen wir jedoch vorerst nicht.
Legen wir so ein Input-Binding zunächst für den ToDo-Titel an. Wir definieren diese in der Klasse unserer Komponente (in der Datei todo-item.ts). Das Binding bekommt den Namen todoTitle, ist vom Typ string und hat standardmäßig einen leeren String als Wert:
export class TodoItem {
@Input() todoTitle: string = "";
}
Damit das funktioniert, müssen wir noch den entsprechenden Import für Input hinzufügen (falls nicht bereits automatisch geschehen):
import { Component, Input } from '@angular/core';
Das gleiche können wir auch noch für die Beschreibung machen (todoDescription). Die ganze Datei todo-item.ts sollte nun so aussehen:
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-todo-item',
imports: [],
templateUrl: './todo-item.html',
styleUrl: './todo-item.scss'
})
export class TodoItem {
@Input() todoTitle: string = "";
@Input() todoDescription: string = "";
}
Nun können wir die entsprechenden Eigenschaften auch schon an unsere Komponente übergeben:
<app-todo-item [todoTitle]="'ToDo 1'" [todoDescription]="'Beschreibung 1'"></app-todo-item>
Um einen String zu übergeben, brauchen wir hier innerhalb der doppelten Anführungszeichen nochmal einfache Anführungszeichen. Eine Zahl würde z.B. nur in doppelten Anführunszeichen stehen.
Auch wenn wir nun jeder Instanz unserer Komponente einen eigenen Titel und eine eigene Beschreibung zuweisen können, werden diese noch nirgends angezeigt. Dafür fehlt noch ein letzter Schritt: wir müssen im HTML unserer Komponente (todo-item.html) die Stellen definieren, an denen der Inhalt der Variablen eingefügt werden soll. Das geht mit doppelten geschweiften Klammern und dem Variablennamen:
<h2>{{ todoTitle }}</h2>
<p>{{ todoDescription }}</p>
<button>✔️ Erledigt</button>
Nun bekommt jede Instanz Komponente ihren eigenen Titel und ihre eigene Beschreibung zugewiesen, ohne dass wir jedes mal den gesamten HTML-Code für das ToDo-Element neu schreiben müssen.
Nun sind wir schon einen großen Schritt weiter: Wir können ToDo-Elemente einfach über unsere Komponente anlegen und individuell mit einem Titel und einer Beschreibung versehen. Doch wir haben immer noch einzelne Einträge fest in unserer HTML-Datei definiert. Das wollen wir nun ändern.
Dafür legen wir zunächst eine Liste mit ein paar Beispiel-Elementen an (zum Hinzufügen von eigenen Elementen kommen wir erst im nächsten Abschnitt). Dies machen wir in Form eines Arrays in der Datei app.ts in der Klasse App:
public todoItems = [
{
title: "ToDo 1",
description: "Beschreibung 1"
},
{
title: "ToDo 2",
description: "Beschreibung 2"
},
{
title: "ToDo 3",
description: "Beschreibung 3"
}
]
Jedes Objekt in diesem Array repräsentiert dabei ein ToDo mit Titel und Beschreibung. Nun möchten wir genau so viele ToDo-Einträge anzeigen, wie sich Objekte in unserem Array befinden und jeweils den Titel und die Beschreibung übernehmen.
Dafür gehen wir wieder in die Datei app.html, löschen alle Instanzen unserer Komponente bis auf eine und umschließen diese mit dem @for-Befehl:
@for (item of todoItems; track item.title) {
<app-todo-item [todoTitle]="item.title" [todoDescription]="item.description"></app-todo-item>
}
Mithilfe von item of todoItems iterieren wir über unser Array, das wir gerade angelegt haben. Über item.title und item.description setzen wir direkt die Werte für Titel und Beschreibung.
Hier sind nun keine zusätzlichen Anführungszeichen mehr nötig, da wir den Variablennamen und nicht den Text selbst übergeben.
Der
@for-Befehl existiert in Angular erst seit kurzem. In früheren Angular-Versionen wurde dafür*ngForinnerhalb des HTML-Tags verwendet (mehr dazu siehe hier).
Nun sollten wir weiterhin eine Liste mit unseren drei ToDos sehen, die sich aber dynamisch anpasst, sobald wir den Inhalt des Arrays ändern.
Um neue ToDo-Einträge über die App hinzufügen zu können, brauchen wir jetzt noch eine Möglichkeit, unserem Array neue Elemente hinzuzufügen, wenn der Nutzer ein neues ToDo eingibt und auf den Button "Hinzufügen" klickt.
Dafür definieren wir zunächst zwei Variablen für den Titel und die Beschreibung (diese brauchen wir im nächsten Schritt) und eine Funktion, mit der wir unserem Array neue Objekte mit dem Titel und der Beschreibung aus diesen Variablen hinzufügen können (in app.ts):
newTodoTitle = "";
newTodoDescription = "";
addTodo(){
if (this.newTodoTitle.trim()) {
this.todoItems.push({
title: this.newTodoTitle.trim(),
description: this.newTodoDescription.trim(),
});
this.newTodoTitle = '';
this.newTodoDescription = '';
}
}
Über
trim()werden Leerzeichen am Anfang und Ende der Eingabe entfernt. Mithilfe der if-Abfrage soll sichergestellt werden, dass nur ToDos hinzugefügt werden, die einen Titel haben (der nicht leer ist oder nur aus Leerzeichen besteht).
Den Inhalt unseres Arrays können wir nun löschen. Dafür müssen wir noch ein sogenanntes Interface angelegen (ITodoItem) und als Typ des Arrays angeben, da TypeScript nun nicht mehr weiß, wie die Elemente des Arrays auszusehen haben.
Außerdem müssen wir noch das FormsModule importieren, um im nächsten Schritt die Eingabefelder auslesen zu können.
Der gesamte Code in app.ts sollte dann folgendermaßen aussehen:
import { Component, signal } from '@angular/core';
import { TodoItem } from './todo-item/todo-item';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
imports: [TodoItem, FormsModule],
templateUrl: './app.html',
styleUrl: './app.scss'
})
export class App {
protected readonly title = signal('TodoApp');
public todoItems: ITodoItem[] = []
newTodoTitle = "";
newTodoDescription = "";
addTodo(){
if (this.newTodoTitle.trim()) {
this.todoItems.push({
title: this.newTodoTitle.trim(),
description: this.newTodoDescription.trim(),
});
this.newTodoTitle = '';
this.newTodoDescription = '';
}
}
}
interface ITodoItem {
title: string;
description: string;
}
Nun müssen wir nur noch unser Eingabe-Formular ein wenig anpassen. Über [(ngModel)] definieren wir für beide Eingabefelder, in welcher Variablen der Wert gespeichert werden soll, der eingegeben wird – das sind genau die beiden Variablen, die wir gerade erstellt haben:
<input [(ngModel)]="newTodoTitle" type="text" placeholder="Titel" class="input-title"/>
<input [(ngModel)]="newTodoDescription" type="text" placeholder="Beschreibung" class="input-description"/>
Über das (click)-Binding müssen wir nun nur noch definieren, was passieren soll wenn wir auf den Button klicken. Dabei soll genau die Funktion aufgerufen werden, die wir gerade zum Hinzufügen von Einträgen angelegt haben:
<button (click)="addTodo()">➕ Hinzufügen</button>
Der gesamte HTML-Code in app.html sollte nun wie folgt aussehen:
<div class="main-container">
<h1>Meine Aufgaben</h1>
<div class="card">
<input [(ngModel)]="newTodoTitle" type="text" placeholder="Titel" class="input-title"/>
<input [(ngModel)]="newTodoDescription" type="text" placeholder="Beschreibung" class="input-description"/>
<button (click)="addTodo()">➕ Hinzufügen</button>
</div>
@for (item of todoItems; track item.title) {
<app-todo-item [todoTitle]="item.title" [todoDescription]="item.description"></app-todo-item>
}
</div>
Wenn wir jetzt einen Titel und eine Beschreibung eingeben, sollten wir sehen, dass das Element der ToDo-Liste hinzugefügt wird.
Bisher können wir zwar neue Einträge zu unserer Liste hinzufügen, aber sie noch nicht als erledigt markieren. Darum kümmern wir uns in diesem Abschnitt.
Um ein ToDo-Element zu entfernen, müssen wir zunächst erkennen, dass der Button "Erledigt" geklickt wurde. Das geht wieder über ein (click)-Binding in todo-item.html:
<button (click)="markDone()">✔️ Erledigt</button>
Die zugehörige Funktion markDone() definieren wir in todo-item.ts. Außerdem legen wir ein Output-Binding an, über das wir ein sogenanntes Event auslösen (in diesem Fall das Event done). Damit können wir der Hauptkomponente (die ja unser ToDo-Array entält) signalisieren, dass wir den Eintrag löschen möchten:
@Output() done = new EventEmitter<void>();
markDone() {
this.done.emit();
}
In unserer app.html geben wir nun an, was passieren soll, wenn dieses Event empfangen wird:
<app-todo-item [todoTitle]="item.title" [todoDescription]="item.description" (done)="removeTodo(item)"></app-todo-item>
Die Funktion removeTodo(item), die wir bei einem done-Event aufrufen, definieren wir in app.ts:
removeTodo(itemToRemove: ITodoItem) {
this.todoItems = this.todoItems.filter(item => item !== itemToRemove);
}
Die Funktion filtert unser Array nach allen Elementen, die nicht dem zu entfernenden Element entsprechen. Anders gesagt: Alle Elemente außer dem zu löschenden Element bleiben in der Liste. Somit wird genau das Element, für das wir auf "Erledigt" geklickt haben, aus der Liste gelöscht und somit auch nicht mehr angezeigt.
Wenn wir nun bei einem unserer ToDos auf den Button klicken, sollte genau dieses Element aus der Liste verschwinden.
Fertig!
Glückwunsch, du hast nun deine erste eigene Angular-App programmiert und die wichtigsten Funktionen des Web-Frameworks kennengelernt!
In den folgenden Abschnitten findest du noch einige Möglichkeiten, wie die ToDo-App erweitert werden kann. Diese würden den Rahmen dieser Einführung allerdings sprengen. Außerdem findest du unten noch ein paar nützliche Links. Wenn du einmal Informationen zu Angular suchst, können dir diese sicherlich helfen.
Natürlich ist unsere ToDo-App so noch nicht ganz für den produktiven Einsatz geeignet: Da unsere ToDos nur in einem Array gespeichert werden, sind sie nach jedem Neustart der App wieder verschwunden. Tatsächlich ist dieses Vorgehen aber typisch für Web-Anwendungen: Die Web-App selbst, die in Angular geschrieben ist (das sogenannte Frontend), speichert selbst keine Daten. Das geht über eine Schnittstelle zum Backend - meist ein Server, der eine Datenbank bereitstellt.
Ein solches Backend mit einer Datenbank zu programmieren und an unsere App anzubinden ist zwar nicht sehr schwierig, würde aber den Rahmen dieses Tutorials sprengen.
Außerdem läuft unsere App momentan nur lokal auf unserem Rechner. Um sie über das Internet aufrufen zu können, müssen wir sie auf einem Server bereitstellen ("hosten"). Dafür müssen wir zuerst einen sogenannten Build ausführen (das geht über den Befehl ng build). Dabei werden aus unserer Anwendung die HTML-, CSS- und JavaScript-Dateien erzeugt, die ein Browser anzeigen kann. Diese können wir dann über einen Webserver (z.B. nginx oder Apache) bereitstellen, sodass man sie über das Internet aufrufen kann. Auch das würde hier allerdings den Rahmen dieses Tutorials sprengen.
Die oben genannten YouTube-Tutorials bieten einen sehr guten Überblick über die Funktionen von Angular. Allerdings kann es vorkommen, dass dort ältere Versionen von Angular verwendet werden und sich somit einzelne Befehle oder Dateinamen unterscheiden können. Die Grundkonzepte bleiben allerdings die gleichen.