navigation Navigation


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 inputs aufsplittet und uns als Array von Strings zurückgibt.

    custom-card.component.ts
    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:

    custom-card.component.html
    <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.

    view-child-example.component.ts
    // 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.

    view-child-example.component.html
    <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.

    Angular Component Queries - viewChild - ausgelesene Werte

    Wenn man auf den Button klick, wird der Inhalt des CustomCardComponent geändert. Durch die Verwendung von viewChild und computedwird der Inhalt automatisch aktualisiert. Bei diesen Funktionen handelt es sich eigentlich um Signale.

    Angular Component Queries - viewChild - aktualisierte Werte

    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.

    custom-button.component.ts
    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.

    custom-button.component.html
    <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.

    view-children-example.component.ts
    // 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.

    view-children-example.component.html
    <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.

    Angular Component Queries - viewChildren - Beispiel

    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.

    highlight-box.component.ts
    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.

    view-children-example.component.html
    <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.

    content-child.component.ts
    // 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());
        }
    
    }