Queries
Angular’s Component Queries ermöglichen es, auf Komponenteninstanzen zuzugreifen und deren Eigenschaften und Methoden zu verwenden. Dies ist besonders nützlich, wenn Sie auf Daten oder Funktionen zugreifen möchten, die in einer anderen Komponente definiert sind.
In diesem Abschnitt werden wir die verschiedenen Möglichkeiten erkunden, wie du auf Komponenteninstanzen zugreifen kannst, um Daten auszugeben.
Wir werden uns auch mit den verschiedenen Arten von Abfragen befassen, die du in Angular verwenden kannst, um auf Komponenteninstanzen zuzugreifen.
Inhaltsverzeichnis
View Queries - viewChild
Um dieses Beispiel ausführlich zu erklären, werden wir ein unabhängiges Component erstellen, von dem wir die Daten auslesen.
Für diesen Zweck erstellen wir eine Komponente “CustomCard”. Diese Komponente statten wir mir einem input
aus, um bestimmten Inhalt hineinzugeben. Außerdem definieren wir eine Methode, die den Inhalt des input
s aufsplittet und uns als Array von Strings zurückgibt.
import { Component, input } from '@angular/core';
@Component({
selector: 'app-custom-card',
imports: [],
templateUrl: './custom-card.component.html',
styleUrl: './custom-card.component.scss'
})
export class CustomCardComponent {
cardContent = input<string>('');
getContentSplitted(): string[] {
return this.cardContent().split("");
}
}
Das Template des CustomCard Components sieht wie folgt aus:
<div class="custom-card">
{{ cardContent() }}
</div>
Nun werden wir eine weitere Komponente ViewChildExampleComponent
erstellen. Diese Komponente wird viewChild
verwenden, um auf die Instanz des CustomCardComponent
zuzugreifen und die Methode getContentSplitted()
aufzurufen.
// Angular
import { Component, computed, viewChild } from '@angular/core';
// Components
import { CustomCardComponent } from './custom-card/custom-card.component';
@Component({
selector: 'app-view-child-example',
imports: [
CustomCardComponent
],
templateUrl: './view-child-example.component.html',
styleUrl: './view-child-example.component.scss'
})
export class ViewChildExampleComponent {
// Referenz auf die CustomCardComponent
customCard = viewChild<CustomCardComponent>(CustomCardComponent);
// Inhalt des CustomCardComponents auslesen
customCardContent = computed(() => this.customCard()?.cardContent());
// Zusätzlich den gesplitteten Inhalt des CustomCardComponents auslesen
customCardContentSplitted = computed(() => this.customCard()?.getContentSplitted());
// Inhalt, den wir initial an die CustomCardComponent übergeben
cardContent = 'Hello card';
/**
* Change the card content
*/
changeCardContent() {
this.cardContent = 'Hello card - changed';
}
}
Im Template der ViewChildExampleComponent
verwenden wir die app-custom-card
Komponente und binden den cardContent
an die CustomCardComponent
. Außerdem fügen wir einen Button hinzu, um den Inhalt zu ändern.
Weiter unten platzieren wir den ausgelesenen, gesplitteten Inhalt des CustomCardComponent
.
<app-custom-card [cardContent]="cardContent" />
<hr>
<button (click)="changeCardContent()">
Change card content
</button>
<hr>
<p>
Content from custom card<br>
<strong>{{ customCardContent() }}</strong>
</p>
<p>
Content splitted<br>
<strong>{{ customCardContentSplitted() }}</strong>
</p>
Das Ergebnis sieht in etwa so aus. Die Inhalte wurden aus dem anderen Component ausgelesen. Zum Einen aus einer Variable und zum Anderen aus einer Methode.
Wenn man auf den Button klick, wird der Inhalt des CustomCardComponent
geändert. Durch die Verwendung von viewChild
und computed
wird der Inhalt automatisch aktualisiert. Bei diesen Funktionen handelt es sich eigentlich um Signale.
View Queries - viewChildren
Im nächsten Beispiel verwenden wir viewChildren
, um auf mehrere Instanzen eines Components zuzugreifen. Auch in diesem Beispiel erstellen wir eine unabhängige Komponente, die wir dann in unserer Beispiel-Komponente verwenden und Werte auslesen.
Als unabhängige Komponente erstellen wir eine CustomButton
Komponente, die wir in der ViewChildrenExampleComponent
verwenden werden.
In dieser Komponente haben wir einen input
mit dem Namen buttonText
, der den Text des Buttons speichert. Außerdem haben wir eine Methode getLowerCaseText()
, die den Text in Kleinbuchstaben zurückgibt.
import { Component, input } from '@angular/core';
@Component({
selector: 'app-custom-button',
imports: [],
templateUrl: './custom-button.component.html',
styleUrl: './custom-button.component.scss'
})
export class CustomButtonComponent {
buttonText = input<string, string>('', {
transform: (value) => value.toUpperCase()
});
getLowerCaseText(): string {
return this.buttonText().toLowerCase();
}
}
Das Template der CustomButtonComponent
sieht wie folgt aus.
<button>{{ buttonText() }}</button>
Nun erstellen wir die ViewChildrenExampleComponent
, in dem wir mehrere Instanzen der CustomButtonComponent
verwenden werden. Wir verwenden viewChildren
, um auf alle Instanzen des CustomButtonComponent
zuzugreifen und deren Methoden aufzurufen.
// Angular
import { AfterViewInit, Component, computed, viewChildren } from '@angular/core';
// Components
import { CustomButtonComponent } from './custom-button/custom-button.component';
@Component({
selector: 'app-view-children-example',
imports: [
CustomButtonComponent
],
templateUrl: './view-children-example.component.html',
styleUrl: './view-children-example.component.scss'
})
export class ViewChildrenExampleComponent implements AfterViewInit {
// Referenz auf alle CustomButtonComponent Instanzen
customButtons = viewChildren<CustomButtonComponent>(CustomButtonComponent);
// Ergebnis der Methode getLowerCaseText() auslesen
customButtonsText = computed(() => this.customButtons().map(button => button.getLowerCaseText()));
// Werte sind direkt nach dem Erstellen der Instanzen noch nicht verfügbar.
// Daher verwenden wir AfterViewInit, um die Werte auszulesen
// und in der Konsole auszugeben.
ngAfterViewInit(): void {
console.log(this.customButtonsText());
}
}
Im Template binden wir app-custom-button
Components ein und übergeben jeweils den buttonText
an die Instanz.
Weiter unten geben wir in einer Schleife den Text der Buttons aus, der durch die Methode getLowerCaseText()
zurückgegeben und in der Variable customButtonsText
gespeichert wird.
<app-custom-button [buttonText]="'Button one'"></app-custom-button>
<app-custom-button [buttonText]="'Button two'"></app-custom-button>
<hr>
@for (btn of customButtonsText(); track btn) {
<p>Ausgelesener Button-Text: {{ btn }}</p>
}
Das Ergebnis sieht in etwa so aus. Die Texte der Buttons wurden aus dem anderen Component ausgelesen.
Content Queries - contentChild
Mit der neuen Signal-Funktion contentChild
ist es möglich in Angular auf ein Component zuzugreifen, welches innerhalb des aktuellen Components verwendet wird.
Um die Funktion besser zu erklären, benötigen wir ein Hilfs-Component, das wir ansprechen werden. Für dieses Beispiel erstellen wir ein Highlight-Box Component, welches einfach bestimmten Inhalt annimmt.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-highlight-box',
imports: [
CommonModule
],
templateUrl: './highlight-box.component.html',
styleUrl: './highlight-box.component.scss'
})
export class HighlightBoxComponent {
isHighlighted: boolean = false;
highlightMessage(): void {
this.isHighlighted = true;
console.log('Message highlighted!');
}
}
Das dazugehörige Template ist simple und sieht die folgt aus. Das hat einfach ein div
Element und ng-content
für die Projektion des Inhalts.
<div class="highlight-box" [ngClass]="{'highlighted': isHighlighted}">
<ng-content></ng-content>
</div>
Im nächsten Schritt wird ein anderes Component erstellt, in welchem wir die Referenz auf anderes Component, in diesem Fall das Highlight-Box Component, erhalten möchten. Ich nenne es hier das Content-Child Component.
// Angular
import { Component, contentChild, AfterContentInit } from '@angular/core';
// Components
import { HighlightBoxComponent } from './highlight-box/highlight-box.component';
import { CustomCardComponent } from './custom-card/custom-card.component';
@Component({
selector: 'app-content-child-example',
imports: [
HighlightBoxComponent
],
templateUrl: './content-child-example.component.html',
styleUrl: './content-child-example.component.scss'
})
export class ContentChildExampleComponent implements AfterContentInit {
highlightBox = contentChild(HighlightBoxComponent);
customCard = contentChild(CustomCardComponent);
ngAfterContentInit(): void {
console.log(this.highlightBox());
console.log(this.customCard());
}
}