Angular Directives - DOM dynamisch steuern
Directives geben dir superpowers um das DOM zu manipulieren! Lerne die wichtigsten Built-in Directives und erstelle eigene.
📋 In diesem Artikel lernst du:
- Was Directives sind und die 3 Typen
- *ngIf - Conditional Rendering
- *ngFor - Listen rendern
- *ngSwitch - Multiple Conditions
- ngClass & ngStyle - Dynamisches Styling
- Custom Directives erstellen
- Best Practices für Directives
Was sind Directives?
Directives sind Anweisungen an Angular, wie das DOM verändert werden soll.
Denke an Directives wie Zauberstäbe: 🪄
- Sie verändern das Aussehen oder Verhalten von Elementen
- Manche fügen Elemente hinzu/entfernen (*ngIf, *ngFor)
- Andere ändern nur Eigenschaften (ngClass, ngStyle)
Die 3 Typen von Directives
-
Component Directives
- Components sind eigentlich Directives mit Template!
<app-user-profile>ist eine Component Directive
-
Structural Directives (mit
*)- Ändern die DOM-Struktur
- Fügen Elemente hinzu/entfernen
*ngIf,*ngFor,*ngSwitch
-
Attribute Directives
- Ändern Aussehen/Verhalten
- Keine Struktur-Änderung
ngClass,ngStyle,ngModel
*ngIf - Conditional Rendering
Zeige/verstecke Elemente basierend auf Bedingungen.
Basic ngIf
export class UserComponent {
isLoggedIn = true;
userName = 'Max';
age = 25;
}
<!-- Zeige nur wenn isLoggedIn true ist -->
<div *ngIf="isLoggedIn">
<h2>Willkommen zurück, {{ userName }}!</h2>
</div>
<!-- Mit Bedingung -->
<p *ngIf="age >= 18">Du bist volljährig</p>
<p *ngIf="age < 18">Du bist minderjährig</p>
Wichtig: Das Element wird aus dem DOM entfernt, nicht nur versteckt!
ngIf mit else
<div *ngIf="isLoggedIn; else loggedOut">
<h2>Willkommen, {{ userName }}!</h2>
</div>
<ng-template #loggedOut>
<h2>Bitte melde dich an</h2>
</ng-template>
Erklärung:
;else loggedOut- Wenn false, zeige Template "loggedOut"<ng-template #loggedOut>- Template-Definition
ngIf mit then und else
<div *ngIf="isLoggedIn; then loggedIn; else loggedOut"></div>
<ng-template #loggedIn>
<h2>Willkommen zurück!</h2>
</ng-template>
<ng-template #loggedOut>
<h2>Bitte anmelden</h2>
</ng-template>
ngIf mit Variable (as)
user$ = {
name: 'Max',
email: 'max@example.com',
role: 'admin'
};
<div *ngIf="user$ as user">
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
<span *ngIf="user.role === 'admin'">Admin-Badge</span>
</div>
Komplexe Bedingungen
<!-- AND -->
<div *ngIf="isLoggedIn && isAdmin">
Admin Panel
</div>
<!-- OR -->
<div *ngIf="isLoading || hasError">
Bitte warten...
</div>
<!-- Vergleiche -->
<div *ngIf="age >= 18 && age <= 65">
Erwerbsfähig
</div>
<!-- Funktionen -->
<div *ngIf="checkPermission('write')">
Bearbeiten erlaubt
</div>
*ngFor - Listen rendern
Iteriere über Arrays und erstelle Elemente für jedes Item.
Basic ngFor
export class UserListComponent {
users = [
{ id: 1, name: 'Max', age: 25 },
{ id: 2, name: 'Anna', age: 30 },
{ id: 3, name: 'Tom', age: 22 }
];
}
<ul>
<li *ngFor="let user of users">
{{ user.name }} ({{ user.age }} Jahre)
</li>
</ul>
Ausgabe:
• Max (25 Jahre)
• Anna (30 Jahre)
• Tom (22 Jahre)
ngFor mit Index
<ul>
<li *ngFor="let user of users; let i = index">
{{ i + 1 }}. {{ user.name }}
</li>
</ul>
Ausgabe:
1. Max
2. Anna
3. Tom
ngFor mit trackBy (Performance!)
export class UserListComponent {
users = [
{ id: 1, name: 'Max', age: 25 },
{ id: 2, name: 'Anna', age: 30 },
{ id: 3, name: 'Tom', age: 22 }
];
// TrackBy Funktion
trackByUserId(index: number, user: any): number {
return user.id; // Nutze eindeutige ID!
}
}
<ul>
<li *ngFor="let user of users; trackBy: trackByUserId">
{{ user.name }}
</li>
</ul>
Warum trackBy?
- Angular weiß welches Element welches ist
- Nur geänderte Elemente werden neu gerendert
- Viel bessere Performance bei großen Listen!
ngFor Spezial-Variablen
<ul>
<li *ngFor="let user of users;
let i = index;
let first = first;
let last = last;
let even = even;
let odd = odd">
<span [class.highlight]="first">
{{ i }}. {{ user.name }}
</span>
<span *ngIf="first">(Erster)</span>
<span *ngIf="last">(Letzter)</span>
<span *ngIf="even">(Gerade Zeile)</span>
<span *ngIf="odd">(Ungerade Zeile)</span>
</li>
</ul>
Verschachtelte ngFor
categories = [
{
name: 'Obst',
items: ['Apfel', 'Birne', 'Orange']
},
{
name: 'Gemüse',
items: ['Karotte', 'Tomate', 'Gurke']
}
];
<div *ngFor="let category of categories">
<h3>{{ category.name }}</h3>
<ul>
<li *ngFor="let item of category.items">
{{ item }}
</li>
</ul>
</div>
Leere Liste behandeln
<div *ngIf="users.length > 0; else noUsers">
<ul>
<li *ngFor="let user of users">
{{ user.name }}
</li>
</ul>
</div>
<ng-template #noUsers>
<p>Keine Benutzer gefunden.</p>
</ng-template>
*ngSwitch - Multiple Conditions
Wie switch-case in TypeScript, aber im Template.
export class StatusComponent {
status = 'loading'; // 'loading', 'success', 'error'
}
<div [ngSwitch]="status">
<p *ngSwitchCase="'loading'">
Lädt...
</p>
<p *ngSwitchCase="'success'">
✓ Erfolgreich geladen!
</p>
<p *ngSwitchCase="'error'">
✗ Fehler beim Laden
</p>
<p *ngSwitchDefault>
Unbekannter Status
</p>
</div>
ngSwitch Beispiel: User-Rolle
userRole = 'admin'; // 'admin', 'editor', 'viewer'
<div [ngSwitch]="userRole">
<div *ngSwitchCase="'admin'">
<h2>Admin Dashboard</h2>
<button>Benutzer verwalten</button>
<button>Einstellungen</button>
</div>
<div *ngSwitchCase="'editor'">
<h2>Editor Dashboard</h2>
<button>Artikel bearbeiten</button>
</div>
<div *ngSwitchCase="'viewer'">
<h2>Viewer Dashboard</h2>
<p>Nur Lesezugriff</p>
</div>
<div *ngSwitchDefault>
<p>Keine Berechtigung</p>
</div>
</div>
ngClass - Dynamische CSS-Klassen
Füge/entferne CSS-Klassen basierend auf Bedingungen.
Object Syntax
export class ButtonComponent {
isActive = true;
isDisabled = false;
isPrimary = true;
}
<button [ngClass]="{
'active': isActive,
'disabled': isDisabled,
'btn-primary': isPrimary,
'btn-secondary': !isPrimary
}">
Click me
</button>
Resultat wenn true:
<button class="active btn-primary">Click me</button>
Array Syntax
buttonClasses = ['btn', 'btn-large', 'btn-primary'];
<button [ngClass]="buttonClasses">
Click me
</button>
String Syntax
classList = 'btn btn-primary active';
<button [ngClass]="classList">
Click me
</button>
Method Syntax
getButtonClasses() {
return {
'btn-success': this.isSuccess,
'btn-danger': this.isError,
'btn-lg': this.isLarge
};
}
<button [ngClass]="getButtonClasses()">
Click me
</button>
Praktisches Beispiel: Todo Item
todo = {
text: 'Angular lernen',
done: true,
important: false
};
<div [ngClass]="{
'todo-item': true,
'done': todo.done,
'important': todo.important,
'pending': !todo.done
}">
{{ todo.text }}
</div>
.todo-item { padding: 10px; margin: 5px; }
.todo-item.done {
text-decoration: line-through;
opacity: 0.6;
}
.todo-item.important {
border-left: 4px solid red;
}
.todo-item.pending {
font-weight: bold;
}
ngStyle - Dynamische Inline-Styles
Setze CSS-Styles dynamisch.
Object Syntax
export class BoxComponent {
backgroundColor = '#3498db';
textColor = '#ffffff';
fontSize = 16;
padding = 20;
}
<div [ngStyle]="{
'background-color': backgroundColor,
'color': textColor,
'font-size.px': fontSize,
'padding.px': padding
}">
Styled Box
</div>
Method Syntax
getStyles() {
return {
'width': this.width + 'px',
'height': this.height + 'px',
'background-color': this.getColor(),
'border-radius': this.rounded ? '8px' : '0'
};
}
getColor() {
return this.isDanger ? 'red' : 'green';
}
<div [ngStyle]="getStyles()">
Dynamic Styles
</div>
Praktisches Beispiel: Progress Bar
export class ProgressBarComponent {
progress = 75; // 0-100
getProgressStyles() {
return {
'width': this.progress + '%',
'background-color': this.getProgressColor(),
'transition': 'width 0.3s ease'
};
}
getProgressColor() {
if (this.progress < 33) return '#e74c3c'; // Rot
if (this.progress < 66) return '#f39c12'; // Orange
return '#27ae60'; // Grün
}
}
<div class="progress-container">
<div class="progress-bar" [ngStyle]="getProgressStyles()">
{{ progress }}%
</div>
</div>
.progress-container {
width: 100%;
height: 30px;
background-color: #ecf0f1;
border-radius: 15px;
overflow: hidden;
}
.progress-bar {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
}
Vollständiges Beispiel: User-Liste mit Filters
export class UserListComponent {
users = [
{ id: 1, name: 'Max', age: 25, status: 'active', role: 'admin' },
{ id: 2, name: 'Anna', age: 30, status: 'active', role: 'editor' },
{ id: 3, name: 'Tom', age: 22, status: 'inactive', role: 'viewer' },
{ id: 4, name: 'Lisa', age: 28, status: 'active', role: 'editor' }
];
filterStatus = 'all'; // 'all', 'active', 'inactive'
showDetails = false;
getFilteredUsers() {
if (this.filterStatus === 'all') {
return this.users;
}
return this.users.filter(u => u.status === this.filterStatus);
}
getRoleBadgeClass(role: string) {
return {
'badge': true,
'badge-admin': role === 'admin',
'badge-editor': role === 'editor',
'badge-viewer': role === 'viewer'
};
}
trackByUserId(index: number, user: any) {
return user.id;
}
}
<div class="user-list">
<h2>Benutzerverwaltung</h2>
<!-- Filter Buttons -->
<div class="filters">
<button
(click)="filterStatus = 'all'"
[ngClass]="{'active': filterStatus === 'all'}">
Alle
</button>
<button
(click)="filterStatus = 'active'"
[ngClass]="{'active': filterStatus === 'active'}">
Aktiv
</button>
<button
(click)="filterStatus = 'inactive'"
[ngClass]="{'active': filterStatus === 'inactive'}">
Inaktiv
</button>
</div>
<!-- User Liste -->
<div *ngIf="getFilteredUsers().length > 0; else noUsers">
<div
*ngFor="let user of getFilteredUsers();
trackBy: trackByUserId;
let i = index;
let odd = odd"
class="user-card"
[ngClass]="{'odd': odd, 'inactive': user.status === 'inactive'}">
<div class="user-header">
<h3>{{ i + 1 }}. {{ user.name }}</h3>
<span [ngClass]="getRoleBadgeClass(user.role)">
{{ user.role }}
</span>
</div>
<div class="user-info">
<p>Alter: {{ user.age }}</p>
<p>
Status:
<span [ngStyle]="{
'color': user.status === 'active' ? 'green' : 'red',
'font-weight': 'bold'
}">
{{ user.status }}
</span>
</p>
</div>
<button
(click)="showDetails = !showDetails"
[class.expanded]="showDetails">
{{ showDetails ? 'Weniger' : 'Mehr' }} Details
</button>
<div *ngIf="showDetails" class="details">
<p>User ID: {{ user.id }}</p>
<p>Erstellt: 01.01.2025</p>
</div>
</div>
</div>
<ng-template #noUsers>
<div class="empty-state">
<p>Keine Benutzer gefunden.</p>
<button (click)="filterStatus = 'all'">
Filter zurücksetzen
</button>
</div>
</ng-template>
</div>
Tipps & Tricks
Performance-Tipps
1. TrackBy immer nutzen bei ngFor:
<!-- ❌ Ohne trackBy - Schlechte Performance -->
<div *ngFor="let item of items">
<!-- ✅ Mit trackBy - Gute Performance -->
<div *ngFor="let item of items; trackBy: trackById">
2. ngIf vs. CSS-hidden:
<!-- ngIf entfernt aus DOM (besser für große Components) -->
<app-heavy-component *ngIf="show"></app-heavy-component>
<!-- CSS versteckt nur (besser fürs Toggle) -->
<div [hidden]="!show">Schnell toggle</div>
3. ngFor Limit:
// Slice Pipe für Pagination
```html
<div *ngFor="let item of items | slice:0:10">
Debugging-Trick
JSON Pipe zum Debuggen:
<div *ngFor="let user of users">
{{ user | json }} <!-- Zeigt komplettes Object -->
</div>
Häufige Fehler
Fehler 1: Mehrere Structural Directives
❌ FALSCH:
<div *ngIf="isVisible" *ngFor="let item of items">
<!-- Funktioniert NICHT! -->
</div>
✅ RICHTIG:
<ng-container *ngIf="isVisible">
<div *ngFor="let item of items">
{{ item }}
</div>
</ng-container>
Regel: Nur EINE Structural Directive pro Element!
Fehler 2: trackBy vergessen
❌ Schlecht für Performance:
<div *ngFor="let user of users">
✅ Besser:
<div *ngFor="let user of users; trackBy: trackByUserId">
Fehler 3: ngClass Syntax-Fehler
❌ FALSCH:
<div [ngClass]="active"> <!-- String statt Object/Array -->
✅ RICHTIG:
<div [ngClass]="{'active': isActive}">
<!-- oder -->
<div [ngClass]="['btn', 'btn-primary']">
Fehler 4: * vergessen bei Structural Directives
❌ FALSCH:
<div ngIf="condition"> <!-- * fehlt! -->
✅ RICHTIG:
<div *ngIf="condition">
Debugging & Troubleshooting
ngIf funktioniert nicht?
Prüfe:
- Ist die Bedingung wirklich true/false?
ngOnInit() {
console.log('Condition:', this.isVisible);
}
- Ist die Variable definiert?
isVisible: boolean = false; // Initialisieren!
ngFor zeigt nichts?
Prüfe:
- Ist das Array leer?
ngOnInit() {
console.log('Items:', this.items, this.items.length);
}
- Console Errors?
ERROR: Cannot read property 'name' of undefined
→ Item hat kein 'name' Property!
ngClass funktioniert nicht?
Prüfe:
- Sind die CSS-Klassen definiert?
.active { background: blue; } /* CSS existiert? */
- Syntax korrekt?
[ngClass]="{ 'active': isActive }" <!-- Quotes um Klasse! -->
Zusammenfassung
Du hast gelernt:
- ✅ Directives ändern das DOM (Struktur oder Attribute)
- ✅ *ngIf für Conditional Rendering (Element hinzufügen/entfernen)
- ✅ *ngFor für Listen (mit trackBy für Performance)
- ✅ *ngSwitch für Multiple Conditions
- ✅ ngClass für dynamische CSS-Klassen
- ✅ ngStyle für dynamische Inline-Styles
- ✅ Nur EINE Structural Directive pro Element
Die wichtigsten Directives:
| Directive | Zweck | Beispiel |
|---|---|---|
*ngIf | Show/Hide Element | <div *ngIf="show"> |
*ngFor | Liste rendern | <li *ngFor="let item of items"> |
*ngSwitch | Multiple Cases | <div [ngSwitch]="status"> |
ngClass | CSS-Klassen | [ngClass]="{'active': isActive}" |
ngStyle | Inline Styles | [ngStyle]="{'color': color}" |
Key Takeaways:
*= Structural Directive (ändert DOM-Struktur)- Nutze
trackBybei ngFor für Performance - ngClass für mehrere Klassen, [class.active] für einzelne
- ng-container für Wrapper ohne Extra-Element
- ng-template für wiederverwendbare Templates
Quiz
📝 Quiz
Welche Directive entfernt ein Element aus dem DOM?
📝 Quiz
Warum sollte man trackBy bei *ngFor nutzen?
Übungsaufgaben
Aufgabe 1: Todo-Liste mit Filters
Erstelle eine Todo-Liste mit:
- *ngFor für die Todos
- *ngIf für "Keine Todos" Nachricht
- Filter Buttons (Alle, Erledigt, Offen)
- ngClass für erledigt/offen Styling
Aufgabe 2: User-Karten
Erstelle User-Cards mit:
- *ngFor über User-Array
- *ngSwitch für User-Rolle (admin/editor/viewer)
- ngClass für Rolle-spezifisches Styling
- trackBy mit User-ID
Aufgabe 3: Progress Dashboard
Erstelle ein Dashboard mit:
- Mehrere Progress-Bars (*ngFor)
- ngStyle für dynamische Breite und Farbe
- *ngIf für Warnung bei < 30%
Nächste Schritte
Im nächsten Artikel:
- Services erstellen
- Dependency Injection verstehen
- Daten zwischen Components teilen
- Singleton vs. Instance Services
➡️ Weiter zu: Angular Services & Dependency Injection
Du meisterst jetzt Directives! 🪄
Gut gemacht! 🎉
Du hast "Angular Directives - DOM dynamisch steuern" abgeschlossen
Artikel bewerten
Bitte einloggen um zu bewerten
Das könnte dich auch interessieren
Angular Basics - Was ist Angular?
Lerne Angular von Grund auf kennen: Was ist Angular, warum Angular, Architektur und Konzepte. Der perfekte Einstieg ins Angular Framework.
Angular Components - Die Bausteine deiner App
Verstehe Angular Components im Detail: Erstellen, strukturieren, Component Lifecycle, Input/Output und Parent-Child Kommunikation.
Angular Data Binding - Daten & UI verbinden
Meistere alle Data Binding Arten in Angular: Interpolation, Property Binding, Event Binding und Two-Way Binding mit ngModel.