Wozu dient die "Sternchen"-Syntax für ngIf, ngFor oder ngSwitchCase Direktiven in Angular

Die Nutzung von strukturellen Direktiven wie *ngIf, *ngFor oder *ngSwitchCase in Angular ist ein zentrales Konzept für die Manipulation der DOM-Struktur. Diese Direktiven sind gekennzeichnet durch das Sternchen/Asterisk-Symbol als Präfix, was sie von regulären Attribut-Direktiven unterscheidet. Doch was genau macht diese Syntax so besonders und warum hat Angular sich für diese spezifische Form entschieden?

Die Sternchen/Asterisk-Syntax, auch bekannt als "Template-Syntax", wird in Angular eingesetzt, um die Verwendung von Structural Directives zu vereinfachen und sie von Attribut-Direktiven unterscheidbar zu machen. Allerdings kann jede strukturelle Direktive mithilfe einer "regulären" Direktive und der Nutzung der <ng-template> Tags implementiert werden. Dieses Vorgehen wird auch von Angular selbst "unter der Haube" angewendet.

In Angular gibt es drei allgemein bekannte strukturelle Direktiven:

*ngIf: Fügt ein Template in den DOM ein, wenn eine bestimmte Bedingung erfüllt ist.

*ngFor: Rendert ein Template für jedes Element in einer Iterable.

*ngSwitchCase: Dient zum Hinzufügen/Entfernen von DOM-Teilbäumen in Abhängigkeit von den Bedingungen im NgSwitch-Ausdruck

Im Folgenden zeigen wir, wie man mithilfe einer korrespondierender Attribut-Direktive und des <ng-template> Elements eine strukturelle Direktive umsetzen kann.

Wie schon erwähnt, wird die *ngIf-Direktive verwendet, um ein Element im DOM basierend auf einer Bedingung anzuzeigen oder das Element komplett zu entfernen. Das sieht in der einfachsten Variante für so aus:

<div *ngIf="test">{{ foo.bar }}</div>

Mit der Attribut-Direktive [ngIf] und <ng-template> umgeschrieben, präsentiert es sich wie folgt:

<ng-template [ngIf]="test">
  <div>{{ foo.bar }}</div>
</ng-template>

Der gleiche Mechanismus funktioniert auch für die *ngFor Direktive:

<ul>
  <li *ngFor="let berry of jberries">
    {{ berry }}
  </li>
</ul>

"Umgeschrieben" mit ngFor und [ngForOf] erhalten wir:
<ng-template ngFor let-berry [ngForOf]="jberries">{{berry}}</ng-template>.
NgFor fügt das Template als eingebettete View (siehe auch: createEmbeddedView) in das DOM für jedes Element in dem jberries-Array. Und mit "let-berry" definiert man wie üblich eine lokale Variable in dem Kontext des Templates.

Als letzes Beispiel untersuchen wir die *ngSwitchCase Direktive:

<div [ngSwitch]="num">
  <span *ngSwitchCase="1">1</span>
  <span *ngSwitchCase="2">2</span>
  <span *ngSwitchDefault>Nope?</span>
</div>
Diese lässt sich mit ng-template und der [ngSwitchCase]-Attribut-Direktive wie folgt umschreiben:
<div [ngSwitch]="num">
  <ng-template [ngSwitchCase]="1">
    <span>1</span>
  </ng-template>
  <ng-template [ngSwitchCase]="2">
    <span>2</span>
  </ng-template>
  <ng-template [ngSwitchCase]="3">
    <span>3</span>
  </ng-template>
  <ng-template ngSwitchDefault>
    Nope?
</ng-template>

Wie man ganz deutlich bei ngSwitchCase sieht, ist der Einsatz von strukturellen Direktiven erheblich platzsparender, was die Lesbarkeit und Wartbarkeit des Codes verbessert. Im Grunde sind sie aber "syntaktischer Zucker" für Attribut-Direktiven in Verbindung mit dem ng-template-Tag.

Die gezeigten Beispiele können auf stackblitz.io ausprobiert werden.
Offiziele Angular Dokumentation zu diesem Thema: https://angular.io/guide/structural-directives#asterisk