Angular @ViewChild: Zugriff auf Child Components, Direktiven und DOM-Elemente

@ViewChild ist ein Angular-Decorator, mit dem sich das Template einer Komponente durchsuchen und die erste passende Child Component, Direktive oder ein natives DOM-Element ermitteln lässt. Dadurch kann die Klasse einer Parent Component programmatisch auf Elemente ihrer eigenen View zugreifen, ohne klassische DOM-Abfragen zu verwenden oder Ereignisse manuell weiterzugeben.

Dieser Leitfaden zeigt, wie @ViewChild innerhalb einer Parent Component verwendet werden kann, um auf eine Child Component, eine Direktive oder ein DOM-Element zuzugreifen. Zusätzlich werden die Optionen static und read, @ViewChildren zusammen mit QueryList sowie die mit Angular 17 eingeführten signalbasierten View Queries behandelt.

Die wichtigsten Punkte zu Angular @ViewChild

  • @ViewChild liefert die erste passende Child Component, Direktive oder das erste entsprechende DOM-Element aus dem eigenen Template einer Komponente.
  • Standardmäßig steht das Ergebnis in ngAfterViewInit zur Verfügung. static: true sollte nur verwendet werden, wenn sich ein Element niemals innerhalb einer strukturellen Direktive befindet und bereits in ngOnInit benötigt wird.
  • @ViewChildren stellt eine QueryList mit allen passenden Elementen bereit. Über QueryList.changes kann auf dynamisch hinzugefügte oder entfernte Elemente reagiert werden.
  • Mit der Option read lässt sich festlegen, welcher Wert von einer Query zurückgegeben wird. Dadurch können beispielsweise ein ElementRef oder eine bestimmte Direktiveninstanz eines gefundenen Elements abgerufen werden.
  • Die signalbasierten Funktionen viewChild() und viewChildren() wurden mit Angular 17 als modernere Alternative eingeführt. Für neue Projekte mit Angular 17 oder einer neueren Version sind sie in der Regel vorzuziehen.
  • Direkte DOM-Manipulationen über ElementRef.nativeElement sollten vermieden werden, wenn sich dieselbe Aufgabe über Angular-Bindings oder Renderer2 umsetzen lässt.

Voraussetzungen

Bevor die folgenden Beispiele umgesetzt werden, sollte die Entwicklungsumgebung folgende Voraussetzungen erfüllen:

  • Node.js 18.x oder neuer sowie eine installierte npm-Version
  • Eine global installierte Angular CLI:

npm install -g @angular/cli
  • Grundkenntnisse zu Angular Components und TypeScript-Decorators

Die Beispiele in diesem Leitfaden wurden mit @angular/core v17 und @angular/cli v17 überprüft.

Was ist @ViewChild und wofür wird es verwendet?

Angular Components kommunizieren in den meisten Fällen über @Input– und @Output-Bindings. Es gibt jedoch Situationen, in denen eine Parent Component eine Methode einer Child Component aufrufen, eine Eigenschaft einer Direktive an einem Template-Element auslesen oder direkt auf einen nativen DOM-Knoten zugreifen muss. Für solche Anwendungsfälle ist @ViewChild vorgesehen.

Ohne @ViewChild könnte ein vergleichbarer Zugriff DOM-Abfragen wie document.querySelector erforderlich machen. Solche direkten Abfragen umgehen die üblichen Change-Detection-Mechanismen von Angular und können die serverseitige Darstellung beeinträchtigen. @ViewChild ist dagegen in den Initialisierungsprozess der Angular View integriert und liefert eine typisierte Referenz, wodurch unsichere direkte DOM-Zugriffe reduziert werden.

So funktioniert das View-Query-System von Angular

Angular erstellt eine Komponente im Wesentlichen in zwei Phasen. In der ersten Phase wird die Komponentenklasse instanziiert und ngOnInit ausgeführt. Die im Template definierten Child-Elemente wurden zu diesem Zeitpunkt jedoch noch nicht vollständig erstellt. In der zweiten Phase initialisiert Angular die View, erzeugt Child Components, bindet Direktiven ein und fügt DOM-Knoten ein. Am Ende dieser zweiten Phase wird ngAfterViewInit ausgeführt. Deshalb stehen Ergebnisse von @ViewChild normalerweise in ngAfterViewInit und nicht bereits in ngOnInit zur Verfügung.

Bei static: false, dem Standardverhalten, wartet Angular bis zu dieser zweiten Phase, bevor die Query aufgelöst wird. Bei static: true wird die Query synchron nach dem ersten Change-Detection-Durchlauf aufgelöst. Dieser Zeitpunkt liegt vor ngAfterViewInit, nachdem das Template bereits kompiliert wurde. Praktische Beispiele für die Option static folgen in einem späteren Abschnitt.

Angular-Beispielprojekt einrichten

Angular-Anwendung erstellen

Erstelle zunächst einen neuen Angular-Workspace:


ng new viewchild-demo –no-standalone –routing=false –style=css

Output:

CREATE viewchild-demo/src/app/app.component.ts (219 bytes)

CREATE viewchild-demo/src/app/app.module.ts (314 bytes)

CREATE viewchild-demo/src/app/app.component.html (23115 bytes)


Wechsle anschließend in das neu angelegte Projektverzeichnis:

Child Component für die Beispiele erstellen

Erstelle eine Child Component, auf die in den folgenden Beispielen zugegriffen werden kann:


ng generate component pup –flat –skip-tests

Output:

CREATE src/app/pup.component.css (0 bytes)

CREATE src/app/pup.component.html (19 bytes)

CREATE src/app/pup.component.ts (188 bytes)

UPDATE src/app/app.module.ts (467 bytes)

Angular ViewChild mit Direktiven verwenden

Wird eine Direktive auf ein Element innerhalb eines Templates angewendet, erhält die Parent Component standardmäßig keine direkte Referenz auf die jeweilige Direktiveninstanz. Mit @ViewChild lässt sich gezielt nach der Direktivenklasse suchen und eine typisierte Referenz auf die Instanz innerhalb der aktuellen View zurückgeben.

Im folgenden Beispiel wird eine SharkDirective erstellt. Sie verwendet ein appShark-Attribut und fügt dem Text des Host-Elements das Wort "Shark" voran. Anschließend nutzt die Parent Component @ViewChild, um eine Eigenschaft dieser Direktiveninstanz auszulesen.

Erstelle die Direktive über @angular/cli:


ng generate directive shark –skip-tests

Der Befehl erstellt die Datei shark.directive.ts und registriert die Direktive in app.module.ts:

app.module.ts

import { SharkDirective } from ‚./shark.directive‘;

@NgModule({

declarations: [

AppComponent,

SharkDirective

],

})

Anschließend werden ElementRef und Renderer2 verwendet, um den angezeigten Text zu verändern. Ersetze den Inhalt von shark.directive.ts durch folgenden Code:

shark.directive.ts

import {

Directive,

ElementRef,

Renderer2

} from ‚@angular/core‘;

@Directive(

{ selector: ‚[appShark]‘ } // selects elements containing the appShark attribute

)

export class SharkDirective {

creature = ‚Dolphin‘; // property that can be read through @ViewChild

constructor(elem: ElementRef, renderer: Renderer2) {

let shark = renderer.createText(‚Shark ‚); // create the text node

renderer.appendChild(elem.nativeElement, shark); // attach it to the host element

}

}

Füge nun das Attribut appShark zu einem span-Element mit Textinhalt hinzu. Ersetze den Inhalt von app.component.html entsprechend:

app.component.html

Wird die Anwendung im Browser geöffnet, erscheint "Shark" vor dem vorhandenen Inhalt des Elements:

Zusätzlich kann die Eigenschaft creature aus SharkDirective ausgelesen und ihrem Wert eine Eigenschaft namens extraCreature zugewiesen werden. Ersetze dazu den Inhalt von app.component.ts durch folgenden Code:

app.component.ts

import {

Component,

ViewChild,

AfterViewInit

} from ‚@angular/core‘;

import { SharkDirective } from ‚./shark.directive‘;

@Component({

selector: ‚app-root‘,

templateUrl: ‚./app.component.html‘,

styleUrls: [‚./app.component.css‘]

})

export class AppComponent implements AfterViewInit {

extraCreature!: string;

@ViewChild(SharkDirective)

set appShark(directive: SharkDirective) {

// this setter runs when Angular resolves the @ViewChild query

this.extraCreature = directive.creature;

};

ngAfterViewInit() {

// the @ViewChild result is guaranteed to be available at this point

console.log(this.extraCreature); // Dolphin

}

}

In diesem Beispiel wird ein Setter verwendet, um die Eigenschaft extraCreature festzulegen. Auf den Wert wird erst im Lifecycle Hook AfterViewInit zugegriffen, da Child Components und Direktiven zu diesem Zeitpunkt verfügbar sind. Anstelle einer direkten Property-Deklaration kommt hier ein Setter zum Einsatz, weil er synchron ausgeführt wird, sobald Angular ein Query-Ergebnis zuweist. Das gilt auch dann, wenn die Direktiveninstanz während der Laufzeit ersetzt wird.

Im Browser wird weiterhin die Meldung "Shark Fin!" angezeigt. In der Konsole erscheint dagegen:

Angular ViewChild mit DOM-Elementen verwenden

Damit ein natives DOM-Element über @ViewChild abgefragt werden kann, muss es zunächst über eine Template-Referenzvariable im Template gekennzeichnet werden. Eine solche lokale Referenz beginnt mit #. Angular verwendet diesen Namen anschließend als Selektor. Ohne eine entsprechende Referenz kann @ViewChild nicht bestimmen, welches Element aus dem Template zurückgegeben werden soll.

Im folgenden Beispiel wird einem <input>-Element die Referenz #someInput zugeordnet. Die Parent Component greift anschließend darauf zu und setzt den Wert des Elements programmatisch:

app.component.html

<input #someInput placeholder=“Your favorite sea creature“>

Das <input>-Element kann nun über ViewChild angesprochen und sein value geändert werden. Ersetze den Inhalt von app.component.ts durch folgenden Code:

app.component.ts

import {

Component,

ViewChild,

AfterViewInit,

ElementRef

} from ‚@angular/core‘;

@Component({

selector: ‚app-root‘,

templateUrl: ‚./app.component.html‘,

styleUrls: [‚./app.component.css‘]

})

export class AppComponent implements AfterViewInit {

@ViewChild(’someInput‘) someInput!: ElementRef;

ngAfterViewInit() {

// nativeElement provides the underlying HTMLInputElement

this.someInput.nativeElement.value = ‚Whale!‘;

}

}

Hinweis: Der direkte Zugriff auf nativeElement umgeht das Sicherheitsmodell von Angular und kann bei serverseitigem Rendering Probleme verursachen. Für DOM-Operationen in produktiven Anwendungen sollte Renderer2 injiziert und über dessen Methoden gearbeitet werden. Muss lediglich eine Eigenschaft gesetzt werden, sind Angular-Template-Bindings wie [value] oder [style] vorzuziehen.

Sobald ngAfterViewInit ausgeführt wird, erhält das <input>-Element folgenden Wert:

Angular ViewChild mit Child Components verwenden

@ViewChild kann einer Parent Component eine typisierte Referenz auf die Instanz einer Child Component bereitstellen. Über diese Referenz lassen sich öffentliche Methoden der Child Component aufrufen oder öffentliche Eigenschaften direkt auslesen, ohne dafür einen Event Emitter oder einen gemeinsamen Service einzusetzen. Dieses Muster eignet sich, wenn die Kommunikation ausschließlich von der Parent Component zur Child Component erfolgt und programmatisch statt durch ein Benutzerereignis ausgelöst wird.

Dieser Abschnitt verwendet die bereits zuvor erstellte PupComponent. Falls dieser Einrichtungsschritt übersprungen wurde, kann die Komponente jetzt erstellt werden:


ng generate component pup –flat –skip-tests

Der Befehl erstellt pup.component.ts, pup.component.css und pup.component.html und registriert die Komponente anschließend in app.module.ts:

app.module.ts


import { PupComponent } from ‚./pup.component‘;

@NgModule({

declarations: [

AppComponent,

PupComponent

],

})

Füge anschließend der PupComponent eine Methode namens whoAmI hinzu, die eine Nachricht zurückgibt:

pup.component.ts

import { Component, OnInit } from ‚@angular/core‘;

@Component({

selector: ‚app-pup‘,

templateUrl: ‚./pup.component.html‘,

styleUrls: [‚./pup.component.css‘]

})

export class PupComponent implements OnInit {

constructor() { }

whoAmI() {

return ‚I am a pup component!‘;

}

ngOnInit(): void {

}

}

Binde danach die Child Component in das Anwendungstemplate ein. Ersetze dazu den Inhalt von app.component.html durch:

app.component.html

Die Parent Component kann nun die Methode whoAmI aufrufen, indem sie über ViewChild die Instanz der Child Component erhält. Ersetze den Inhalt von app.component.ts durch:

app.component.ts

import {

Component,

ViewChild,

AfterViewInit

} from ‚@angular/core‘;

import { PupComponent } from ‚./pup.component‘;

@Component({

selector: ‚app-root‘,

templateUrl: ‚./app.component.html‘,

styleUrls: [‚./app.component.css‘],

})

export class AppComponent implements AfterViewInit {

// typed reference pointing to the child component instance

@ViewChild(PupComponent) pup!: PupComponent;

ngAfterViewInit() {

// invoke a public method directly on the child component

console.log(this.pup.whoAmI()); // I am a pup component!

}

}

Wird die Anwendung ausgeführt, erscheint in der Browser-Konsole:

Output

I am a pup component!

Die static-Option von Angular @ViewChild verstehen

static: true im Vergleich zu static: false

Die Einstellung static legt fest, wann Angular eine @ViewChild-Query in Bezug auf die Change Detection auflöst.

Option Auflösung Verfügbar in Geeignet, wenn
static: false (Standard) Nach dem ersten Change-Detection-Durchlauf ngAfterViewInit Das Element befindet sich innerhalb von *ngIf, *ngFor oder einer anderen strukturellen Direktive
static: true Vor dem ersten Change-Detection-Durchlauf ngOnInit Das Element ist dauerhaft vorhanden und nicht von einer strukturellen Direktive umgeben

Praktisches Beispiel für den Unterschied

Bei static: false, dem Standardwert, wird das Query-Ergebnis in ngAfterViewInit verwendet:

// app.component.ts

@ViewChild(‚myElement‘) myElement!: ElementRef; // static: false is used by default

ngOnInit() {

console.log(this.myElement); // undefined: the query has not been resolved yet

}

ngAfterViewInit() {

console.log(this.myElement); // ElementRef: resolved after view initialization

}

Wird static: true gesetzt, ist die Referenz bereits innerhalb von ngOnInit verfügbar:

// app.component.ts

@ViewChild(‚myElement‘, { static: true }) myElement!: ElementRef;

ngOnInit() {

console.log(this.myElement); // ElementRef: resolved before change detection

}

Für ein Element innerhalb einer strukturellen Direktive sollte static: true nicht verwendet werden. Angular kann eine solche Query nicht vor der Change Detection auflösen, wenn das entsprechende Element zu diesem Zeitpunkt möglicherweise noch nicht im DOM vorhanden ist.

Mit der read-Option den Rückgabetyp von @ViewChild ändern

Der standardmäßige Rückgabetyp einer @ViewChild-Query richtet sich danach, was Angular am gefundenen Element erkennt. Entspricht der Selektor einer Komponente, wird die Komponenteninstanz zurückgegeben. Wird eine Direktive gefunden, liefert Angular die Direktiveninstanz. Mit der Option read lässt sich dieses Verhalten überschreiben. Typische Einsatzfälle sind der Zugriff auf das zugrunde liegende ElementRef eines Elements, auf dem eine Komponente liegt, oder die Auswahl einer bestimmten Direktive, wenn mehrere Direktiven auf dasselbe Element angewendet werden.

Ein ElementRef über einen Komponenten-Selektor auslesen

Dieser Ansatz eignet sich, wenn anstelle der Komponenteninstanz das Host-DOM-Element benötigt wird, beispielsweise um dessen Abmessungen zu ermitteln oder einen nativen DOM-Knoten an eine externe Bibliothek zu übergeben.

// app.component.ts

// Without read, the query returns a PupComponent instance.

// With read: ElementRef, the query returns the component’s host DOM element.

@ViewChild(PupComponent, { read: ElementRef }) pupElement!: ElementRef;

ngAfterViewInit() {

console.log(this.pupElement.nativeElement.tagName); // APP-PUP

}

Eine Direktive von einem Element auslesen

Wenn auf demselben Element mehrere Direktiven verwendet werden, kann mit read bestimmt werden, welche Direktiveninstanz zurückgegeben werden soll.

Füge #myRef und appShark demselben Element in app.component.html hinzu:

app.component.html

Anschließend lässt sich die auf diesem Element vorhandene Instanz von SharkDirective abfragen:

// app.component.ts

@ViewChild(‚myRef‘, { read: SharkDirective }) sharkDir!: SharkDirective;

ngAfterViewInit() {

console.log(this.sharkDir.creature); // Dolphin

}

Mehrere Elemente mit @ViewChildren und QueryList abfragen

@ViewChild liefert lediglich das erste passende Ergebnis. Wenn mehrere Elemente denselben Selektor verwenden und Referenzen auf alle Treffer benötigt werden, kommt @ViewChildren zum Einsatz.

Eine @ViewChildren-Query definieren

Platziere zwei <app-pup>-Komponenten im Template und frage beide gemeinsam ab:

app.component.html

<app-pup></app-pup>
<app-pup></app-pup>

app.component.ts

import {

Component,

ViewChildren,

AfterViewInit,

QueryList

} from ‚@angular/core‘;

import { PupComponent } from ‚./pup.component‘;

@Component({

selector: ‚app-root‘,

templateUrl: ‚./app.component.html‘,

styleUrls: [‚./app.component.css‘]

})

export class AppComponent implements AfterViewInit {

// contains every PupComponent instance found in the template

@ViewChildren(PupComponent) pups!: QueryList;

ngAfterViewInit() {

console.log(this.pups.length); // 2

}

}

Über eine QueryList iterieren

Mit .forEach() kann nach der Initialisierung synchron auf jede gefundene Instanz zugegriffen werden. Dies lässt sich beispielsweise nutzen, um für jedes Child eine Initialisierungsmethode aufzurufen oder einen anfänglichen Eigenschaftswert auszulesen:


ngAfterViewInit() {

this.pups.forEach((pup, index) => {

console.log(`Pup ${index}:`, pup.whoAmI());

});

}

Änderungen einer QueryList abonnieren

QueryList stellt ein Observable namens changes bereit. Dieses gibt eine neue QueryList aus, sobald Elemente zur gefundenen Menge hinzugefügt oder daraus entfernt werden. Das kann beispielsweise geschehen, wenn eine *ngIf-Bedingung eine Child Component in die View einfügt oder wieder entfernt. Beim ersten Rendern wird changes nicht ausgelöst; Ausgaben erfolgen erst bei späteren Änderungen.


ngAfterViewInit() {

// runs whenever a PupComponent enters or leaves the view

this.pups.changes.subscribe((list: QueryList) => {

console.log(‚Pup count:‘, list.length);

});

}

Kann die Komponente zerstört werden, während das Abonnement noch aktiv ist, sollte die Subscription gespeichert und in ngOnDestroy beendet werden, um ein Memory Leak zu vermeiden:

import { Subscription } from ‚rxjs‘;

private pupSub!: Subscription;

ngAfterViewInit() {

this.pupSub = this.pups.changes.subscribe((list: QueryList) => {

console.log(‚Pup count:‘, list.length);

});

}

ngOnDestroy() {

this.pupSub.unsubscribe();

}

Signalbasierte View Queries in Angular 17+

Mit Angular 17 wurden viewChild() und viewChildren() als signalbasierte Alternativen zu @ViewChild und @ViewChildren eingeführt.

viewChild() im Vergleich zu @ViewChild

Merkmal @ViewChild viewChild()
Rückgabetyp Direkte Referenz Signal<T | undefined>
ngAfterViewInit erforderlich Ja Nein
Unterstützung für zoneless Anwendungen Eingeschränkt Ja
Verfügbar seit Angular 2 Angular 17

@ViewChild kann auch in zoneless Anwendungen eingesetzt werden. Ändert sich jedoch eine abgefragte Referenz, muss die Change Detection über ChangeDetectorRef.markForCheck() manuell benachrichtigt werden, weil ohne Zone.js keine automatische Erkennung ausgelöst wird. Das signalbasierte viewChild() ist direkt mit dem reaktiven Graphen von Angular verbunden und kann ohne diesen manuellen Schritt aktualisiert werden.

Grundlegendes Beispiel für eine Signal Query

Das folgende Beispiel verwendet eine Standalone Component. Die signalbasierte API ist für das Standalone-Komponentenmodell vorgesehen und sollte nicht in app.module.ts deklariert werden.

Zusätzlich wird afterNextRender verwendet. Dabei handelt es sich um eine mit Angular 17 eingeführte Lifecycle-Funktion, die einen Callback einmal nach Abschluss des nächsten DOM-Renderzyklus ausführt. In Umgebungen ohne klassenbasierten Lifecycle, beispielsweise bei signalbasierten Standalone Components, kann sie anstelle von ngAfterViewInit eingesetzt werden. afterNextRender eignet sich, wenn nach dem ersten Rendern einmalig DOM-Daten gelesen oder verändert werden müssen. Während des serverseitigen Renderings wird die Funktion nicht ausgeführt.

app.component.ts

import { Component, viewChild, ElementRef, afterNextRender } from ‚@angular/core‘;

@Component({

selector: ‚app-root‘,

template: „,

standalone: true

})

export class AppComponent {

// viewChild() provides a Signal

nameInput = viewChild(’nameInput‘);

constructor() {

afterNextRender(() => {

// retrieve the signal value after the view has rendered

console.log(this.nameInput()?.nativeElement.value);

});

}

}

Ist garantiert, dass ein Element vorhanden ist, kann mit viewChild.required() die undefined-Alternative entfernt werden:


// Signal: throws an error when the query has no match

nameInput = viewChild.required(’nameInput‘);

Wann signalbasierte Queries sinnvoll sind

Bei neuen Anwendungen mit Angular 17 oder einer neueren Version können viewChild() und viewChildren() bevorzugt werden, insbesondere bei zoneless Change Detection oder beim Einsatz von Standalone Components. Projekte mit Angular 16 oder älter sollten weiterhin @ViewChild und @ViewChildren verwenden.

Das folgende Beispiel zeigt, wie viewChildren() ein Signal mit mehreren gefundenen Elementen bereitstellt. In signalbasierten Komponenten kann es @ViewChildren ersetzen. Vor der Ausführung dieses Beispiels wird eine ChildComponent mit ng generate component child --flat --skip-tests --standalone erzeugt:

app.component.ts

import { Component, viewChildren, afterNextRender } from ‚@angular/core‘;

import { ChildComponent } from ‚./child.component‘;

@Component({

selector: ‚app-root‘,

template: `

`,

standalone: true,

imports: [ChildComponent]

})

export class AppComponent {

// viewChildren() provides Signal<readonlyarray>

children = viewChildren(ChildComponent);

constructor() {

afterNextRender(() => {

console.log(this.children().length); // 2

});

}

}

@ViewChild vs. @ContentChild vs. @ViewChildren

Decorator / Funktion Abfragebereich Rückgabe Anzahl Verfügbar in
@ViewChild Eigenes Template der Komponente Erster passender Treffer Einzelnes Element ngAfterViewInit oder ngOnInit mit static: true
@ViewChildren Eigenes Template der Komponente QueryList<T> Mehrere Elemente ngAfterViewInit
@ContentChild Über <ng-content> projizierter Inhalt Erster passender Treffer Einzelnes Element ngAfterContentInit
viewChild() Eigenes Template der Komponente Signal<T> Einzelnes Element Beim Auslesen in Angular 17+
viewChildren() Eigenes Template der Komponente Signal<ReadonlyArray<T>> Mehrere Elemente Beim Auslesen in Angular 17+

@ContentChild eignet sich für wiederverwendbare Wrapper Components, die projizierte Inhalte aufnehmen. Für Elemente, die direkt im eigenen Template einer Komponente definiert sind, werden @ViewChild oder viewChild() verwendet.

Häufige Fehler bei Angular @ViewChild und wie sie vermieden werden

Auf @ViewChild vor ngAfterViewInit zugreifen

Wird eine @ViewChild-Eigenschaft bereits innerhalb von ngOnInit verwendet, ist ihr Wert normalerweise undefined, da Angular die View zu diesem Zeitpunkt noch nicht initialisiert hat.

Falsch:


// app.component.ts

ngOnInit() {

// TypeError: properties of undefined cannot be read

console.log(this.someInput.nativeElement.value);

}

Richtig:

// app.component.ts

ngAfterViewInit() {

console.log(this.someInput.nativeElement.value); // behaves as expected

}

Die Zugriffslogik sollte nach ngAfterViewInit verschoben werden. Zu diesem Zeitpunkt garantiert Angular, dass die View initialisiert und die Query aufgelöst wurde.

Elemente innerhalb von *ngIf oder *ngFor abfragen

Wird für eine Query auf ein Element innerhalb einer strukturellen Direktive static: true gesetzt, versucht Angular die Referenz bereits aufzulösen, obwohl das Element möglicherweise noch gar nicht vorhanden ist.

Falsch:


// app.component.ts

@ViewChild(‚conditionalEl‘, { static: true }) el!: ElementRef;

// static: true cannot resolve an element before *ngIf has potentially rendered it

Richtig:


// app.component.ts

@ViewChild(‚conditionalEl‘) el: ElementRef | undefined;

// static: false is the default and resolves after change detection

ngAfterViewInit() {

if (this.el) {

this.el.nativeElement.focus();

}

}

Die Kombination aus static: false und einer Prüfung auf undefined stellt sicher, dass die Referenz erst verwendet wird, wenn das entsprechende Element tatsächlich im DOM vorhanden ist.

ElementRef nicht verwenden, wenn @Input oder @Output ausreichen

Eine Child Component über read: ElementRef direkt zu verändern, ist unnötig, wenn dasselbe Ergebnis über ein @Input-Binding erreicht werden kann.

Falsch:

// app.component.ts

// Retrieves the host through read: ElementRef and modifies its style directly.

@ViewChild(PupComponent, { read: ElementRef }) pupEl!: ElementRef;

ngAfterViewInit() {

this.pupEl.nativeElement.style.color = ‚red‘;

}

Richtig:


// pup.component.ts

import { Input } from ‚@angular/core‘;

export class PupComponent {

@Input() highlightColor: string = “;

}

// pup.component.html

// {{ message }}



<!– app.component.html –>
<app-pup [highlightColor]=“‚red’“></app-pup>

Wird der Wert über @Input übergeben, bleiben Parent Component und Child Component voneinander entkoppelt. Gleichzeitig bleiben die Change-Detection- und Sicherheitsmechanismen von Angular erhalten.

Häufig gestellte Fragen zu Angular @ViewChild

Was ist der Unterschied zwischen @ViewChild und @ContentChild in Angular?

@ViewChild durchsucht Elemente, die direkt im eigenen Template einer Komponente definiert sind. @ContentChild durchsucht dagegen Elemente, die über <ng-content> in eine Komponente projiziert werden. @ContentChild ist daher für wiederverwendbare Wrapper Components geeignet, die projizierte Inhalte von einer Parent Component erhalten.

Warum ist meine @ViewChild-Eigenschaft in ngOnInit undefined?

Standardmäßig wird @ViewChild erst nach der Initialisierung der View aufgelöst. Dieser Vorgang findet nach ngOnInit statt. Die Logik, die auf die Referenz zugreift, sollte deshalb nach ngAfterViewInit verschoben werden. Wird der Zugriff ausdrücklich bereits in ngOnInit benötigt, kann static: true gesetzt werden. Das gilt jedoch nur, wenn sich das abgefragte Element nicht innerhalb einer strukturellen Direktive befindet.

Was bewirkt die Option static bei @ViewChild?

static: true weist Angular an, die Query vor der Change Detection aufzulösen. Dadurch steht das Ergebnis bereits in ngOnInit zur Verfügung. static: false ist der Standardwert und führt dazu, dass die Query erst nach der Change Detection aufgelöst wird und damit in ngAfterViewInit verfügbar ist. Für Elemente innerhalb von *ngIf oder *ngFor sollte static: false eingesetzt werden.

Wie kann ich auf mehrere Child-Elemente mit demselben Selektor zugreifen?

Verwende @ViewChildren anstelle von @ViewChild. Dadurch wird eine QueryList mit allen passenden Elementen zurückgegeben. Über .forEach() können die Elemente durchlaufen werden, während ein Abonnement von .changes auf spätere Änderungen der Liste reagieren kann.

Ist die direkte DOM-Manipulation über ElementRef aus @ViewChild sicher?

Direkte DOM-Manipulationen über ElementRef.nativeElement umgehen das Sicherheitsmodell von Angular und können serverseitiges Rendering beeinträchtigen. Für DOM-Operationen sollte deshalb der Angular-Service Renderer2 verwendet werden. Alternativ sind Angular-Bindings wie [style], [class] oder @HostBinding vorzuziehen, wenn sich die gewünschte Funktion damit umsetzen lässt.

Was ist die signalbasierte Alternative zu @ViewChild in Angular 17+?

Angular 17 führte viewChild() als reaktive Alternative zu @ViewChild ein. Die Funktion gibt ein Signal zurück, das Änderungen des abgefragten Elements automatisch widerspiegelt und direkt mit dem signalbasierten Reaktivitätsmodell von Angular zusammenarbeitet. Für neue Projekte mit Angular 17 oder einer neueren Version kann diese Variante verwendet werden.

Kann @ViewChild ein Element innerhalb eines *ngIf-Blocks abfragen?

Ja. Die Query muss dafür static: false verwenden, was gleichzeitig der Standardwert ist. Ist die *ngIf-Bedingung false und wird das Element daher nicht gerendert, hat die @ViewChild-Eigenschaft den Wert undefined. Vor dem Zugriff sollte deshalb immer geprüft werden, ob die Referenz tatsächlich vorhanden ist.

Wofür wird die Option read bei @ViewChild verwendet?

Mit read wird festgelegt, welchen Typ Angular für das gefundene Element zurückgeben soll. So liefert beispielsweise @ViewChild('myRef', { read: ElementRef }) ein ElementRef, selbst wenn der Selektor eigentlich eine Komponente identifiziert. @ViewChild('myRef', { read: MyDirective }) gibt dagegen die Instanz der angegebenen Direktive zurück, die auf dem Element angewendet wurde.

Fazit zu Angular @ViewChild

Dieser Leitfaden hat gezeigt, wie @ViewChild innerhalb einer Parent Component eingesetzt werden kann, um auf eine Child Component, eine Direktive oder ein natives DOM-Element zuzugreifen. Außerdem wurden die Optionen static und read, die Abfrage mehrerer Elemente über @ViewChildren und QueryList sowie die mit Angular 17 verfügbare signalbasierte API viewChild() behandelt.

Mit diesen Techniken lassen sich typisierte Referenzen auf Elemente innerhalb eines Komponenten-Templates abrufen. Gleichzeitig kann gesteuert werden, wann Queries im Verhältnis zum Angular-Initialisierungszyklus aufgelöst werden. Abhängig von der verwendeten Angular-Version kann zwischen den decoratorbasierten und den signalbasierten Query-APIs gewählt werden.

Quelle: digitalocean.com

Jetzt 200€ Guthaben sichern

Registrieren Sie sich jetzt in unserer ccloud³ und erhalten Sie 200€ Startguthaben für Ihr Projekt.

Das könnte Sie auch interessieren:

Moderne Hosting Services mit Cloud Server, Managed Server und skalierbarem Cloud Hosting für professionelle IT-Infrastrukturen

Weaviate vs. OpenSearch vs. pgvector im Vergleich

AI/ML, Tutorial
Vijonavor 2 Stunden Weaviate, OpenSearch und PostgreSQL mit pgvector im Vergleich für Vektor- und Hybrid-Suche Wenn eine Anwendung Suchfunktionen benötigt, kommen häufig Werkzeuge infrage, die bereits Teil der vorhandenen Infrastruktur sind.…