Zum Inhalt springen
Auf dieser Seite

Angular - Content Projection

Content Projection erlaubt in Angular, eine Komponente in eine andere einzufügen. Das verändert, wie Angular-Entwickler ihre Anwendungen und Bibliotheken gestalten: hin zu flexiblen, wiederverwendbaren Komponenten.

Dieser Beitrag erklärt die verschiedenen Typen der Content Projection, wann man welchen verwendet, anhand eines Beispiels.

Typen der Content Projection:

Single-Slot Content Projection

Bei diesem Typ steht nur ein Slot zur Verfügung, in den eine Komponente in die Container-Komponente eingefügt werden kann.

Nehmen wir an, Sie haben eine Footer-Komponente, die eine Art Content Component (Kind) enthalten muss. Es gibt viele Szenarien, in denen die Content Projection hier von Anfang an sinnvoll ist:

  • Die Content Component ist noch nicht definiert. Es könnte ein Button, ein Text-Label, ein Select, ein Link, ein Icon oder ein Bild sein.
  • Sie arbeiten im Team, die Aufgaben werden aufgeteilt, und Sie implementieren die Footer-Komponente, während ein anderer Entwickler die Content Component implementiert.
  • Die Content Component ist definiert, und Sie arbeiten allein am Footer, aber Sie möchten sicherstellen, dass diese beiden Komponenten nicht stark gekoppelt sind, sodass es möglich ist, eine von ihnen zu ersetzen, ohne eine der beiden neu implementieren oder ändern zu müssen.

Die Footer-Komponente erhält einen Slot, in den eine Content Component mit ng-content eingefügt werden kann:

import { Component } from '@angular/core';

@Component({
  selector: 'app-footer',
  template: `
  <div class="footer">
    <ng-content></ng-content>   // content slot
  </div>
`
})
export class FooterComponent {}

Die Content Component kann beliebig sein, und um den Fokus auf das Thema Content Projection zu behalten, nehmen wir an, dass es sich um einen einfachen “about”-Button handelt:

import { Component } from '@angular/core';

@Component({
  selector: 'app-button',
  template: `
    <button>about</button>
  `
})
export class ButtonComponent {}

Die Footer-Komponente kann nun innerhalb der App-Komponente verwendet werden, und die Button-Komponente kann eingefügt/projiziert werden:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-footer>
      <app-button></app-button>
    </app-footer>
  `
})
export class AppComponent {}

Das war’s.

Wenn sich die Anforderungen ändern und der Footer einen Text-Link anstelle des Buttons haben muss, muss nur die neue Content Component implementiert und dann anstelle der Button-Komponente in der Footer-Komponente projiziert werden.

Nach oben

Multi-Slot Content Projection:

Dieser Projektionstyp erlaubt das Einfügen mehrerer Content Componentn in die Container-Komponente. Das bedeutet, dass es mehr als einen ng-Content-Slot gibt.

Setzen wir das vorherige Footer-Beispiel fort und nehmen an, dass sich die Anforderungen erneut geändert haben und der Footer gleichzeitig einen Button links und einen Text-Link rechts haben muss. Die Footer-Komponente, eine Button-Komponente und eine Text-Link-Komponente sind bereits vorhanden.

Um mehrere Inhalte zu projizieren, muss die Footer-Komponente aktualisiert werden und in diesem Fall zwei Slots akzeptieren, wobei jeder Slot ein select-Attribut erhält, das bestimmt, welcher Inhalt in welchem Slot gerendert wird:

import { Component } from '@angular/core';

@Component({
  selector: 'app-footer',
  style: `
    .footer {
      display: flex;
      justify-content: space-between;
    }
  `,
  template: `
  <div class="footer">
    <ng-content select=[left]></ng-content>
    <ng-content select=[right]></ng-content>
  </div>
`
})
export class FooterComponent {}

Diese Attribute (left, right) legen fest, welcher Inhalt wo gerendert wird. Um die Anforderung zu erfüllen, sollte der Button das Attribut left erhalten und die Link-Komponente das Attribut right.

import { Component } from '@angular/core';

@Component({
  selector: 'app-button',
  template: `
    <button>about</button>
  `
})
export class ButtonComponent {}

@Component({
  selector: 'app-link',
  template: `
    <a href="#">about</a>
  `
})
export class LinkComponent {}

@Component({
  selector: 'app-root',
  template: `
    <app-footer>
      <app-button left></app-button>
      <app-link right></app-link>
    </app-footer>
  `
})
export class AppComponent {}

Diese Implementierung bietet enorme Flexibilität und Entkopplung der Komponenten. Zum Beispiel ist es sehr einfach, die Positionen der Content Componentn zu tauschen oder eine der Content Componentn zu ersetzen, ohne die gesamte Struktur neu implementieren zu müssen.

Nach oben

Bedingte Content Projection:

Bei diesem Projektionstyp steuert eine Bedingung, welcher Inhalt im Slot der Container-Komponente gerendert wird. Diese Bedingung kann mit einer ng-if-Anweisung erstellt werden.

Um bedingte Content Projection zu verwenden, müssen ng-container und ng-template verwendet werden.

Durch die Verwendung von ng-content initialisiert Angular die Content Component immer, auch wenn sie sich innerhalb einer ng-if-Anweisung befand.

Durch die Verwendung von ng-container oder ng-template rendert Angular die Content Component nur, wenn es ausdrücklich dazu aufgefordert wird.

Kommen wir wieder zum Footer-Komponenten-Beispiel und ändern die Anforderung diesmal so, dass nur ein Inhalt gleichzeitig angezeigt werden kann, abhängig von einer Bedingung.

Um diese Anforderungen umzusetzen, muss die Änderung erfolgen

@HostListener('window:resize', ['$event'])
onResize(event) {
  this.innerWidth = window.innerWidth;
}

Nach oben