Jede Angular-Komponente wird in ein HTML-Element im DOM gerendert – dieses Element nennt man das Host-Element (z. B. <app-button>). Während du im Template der Komponente vollen Zugriff auf das Innere der Komponente hast, musst du spezielle Techniken anwenden, um Attribute, Klassen oder Events direkt auf dem Host-Element selbst zu setzen. Dieser Artikel zeigt dir die modernen und klassischen Methoden dafür.
Binding mit der host Eigenschaft (Modern)
Der von Angular empfohlene Weg, um mit dem Host-Element zu interagieren, ist die host-Eigenschaft innerhalb des @Component-Dekorators. Sie bündelt alle Host-Bindings übersichtlich an einem Ort.
Du kannst dort statische Attribute, dynamische Bindings (wie Klassen oder Styles) und Event-Listener definieren.
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-custom-slider',
template: `<div>Slider Inhalt</div>`,
host: {
// Statisches Attribut (wird immer so gerendert: role="slider")
'role': 'slider',
// Dynamisches Klassen-Binding (Klasse 'active' wird gesetzt, wenn isActive() true ist)
'[class.active]': 'isActive()',
// Dynamisches Style-Binding
'[style.background]': `hasError() ? 'red' : 'green'`,
// Attribut-Binding
'[attr.aria-valuenow]': 'value',
// Event-Listener (lauscht auf Tastatur-Events auf dem Host-Tag)
'(keydown)': 'updateValue($event)'
},
standalone: true
})
export class CustomSliderComponent {
value: number = 0;
isActive = signal(false);
hasError = signal(false);
updateValue(event: KeyboardEvent) {
// Event verarbeiten
}
}Globale Event-Listener
Du kannst über die host-Eigenschaft auch auf globale Events wie das window oder document lauschen:
host: {
// Lauscht auf Scroll-Events des gesamten Fensters
'(window:scroll)': 'onWindowScroll($event)',
// Lauscht auf Klicks irgendwo im Dokument
'(document:click)': 'onDocumentClick($event)'
}@HostBinding und @HostListener (Klassisch)
In vielen bestehenden Projekten findest du stattdessen die Dekoratoren @HostBinding und @HostListener. Sie funktionieren exakt genauso wie die host-Eigenschaft, verteilen die Logik aber über die gesamte TypeScript-Klasse.
import { Component, HostBinding, HostListener } from '@angular/core';
@Component({
selector: 'app-legacy-slider',
template: `...`
})
export class LegacySliderComponent {
// Bindet die Eigenschaft "value" an das aria-valuenow Attribut des Hosts
@HostBinding('attr.aria-valuenow') value: number = 0;
// Dynamisches Setzen des tabIndex
@HostBinding('tabIndex') get tabIndex() {
return this.isDisabled ? -1 : 0;
}
isDisabled = false;
// Lauscht auf keydown Events des Hosts
@HostListener('keydown', ['$event'])
updateValue(event: KeyboardEvent) {
// ...
}
}Kollisionen: Wer gewinnt?
Es kann vorkommen, dass eine Komponente ein Host-Binding definiert, der Entwickler aber beim Verwenden der Komponente dasselbe Attribut nochmals von außen setzt.
Beispiel – Die Komponente definiert intern:
host: { 'role': 'presentation', '[id]': 'id' }
Und wird im HTML so aufgerufen:
<app-photo role="group" [id]="otherId" />
Die Regeln zur Konfliktauflösung lauten:
- Wenn beide Werte statisch sind (
role="presentation"intern vs.role="group"extern), gewinnt der äußere (externe) Wert. - Wenn ein Wert statisch und der andere dynamisch ist, gewinnt der dynamische Wert.
- Wenn beide Werte dynamisch sind, gewinnt das interne Host-Binding der Komponente.
Statische Attribute auslesen (HostAttributeToken)
Wenn du in deiner Komponente ein statisches HTML-Attribut (kein Input-Binding!) auslesen möchtest, das der Host-Komponente übergeben wurde, kannst du das HostAttributeToken zusammen mit inject() verwenden.
Das ist sehr performant, da Angular hierfür keinen Change-Detection-Zyklus benötigt.
import { Component, HostAttributeToken, inject } from '@angular/core';
@Component({
selector: 'app-button',
template: `<button>Klick mich</button>`,
standalone: true
})
export class ButtonComponent {
// Liest das statische Attribut "variation" aus (z.B. <app-button variation="primary">)
// Wirft einen Fehler, wenn das Attribut fehlt!
variation = inject(new HostAttributeToken('variation'));
// Mit optionalem Fallback:
// variation = inject(new HostAttributeToken('variation'), { optional: true }) ?? 'default';
}