Angular: Vorteile der überarbeiteten Control-Flow-Elemente

Was ist Angular?

Das von Google entwickelte Web-Framework Angular unterstützt Entwickler:innen bei der Erstellung von Single-Page-Webanwendungen. Basierend auf TypeScript, bietet es eine Vielzahl an Funktionen und Tools ausgerichtet auf die Optimierung des Entwicklungsflows. Dabei ermöglicht Angular eine effiziente Zwei-Wege-Datenbindung und vereinfacht die Synchronisierung der Benutzeroberfläche mit dem zugrunde liegenden Datenmodell.

Nglf, NgFor und NgSwitch

Wer sich auf die Reise in die Welt von Angular begibt, stößt bald auf die Control-Flow-Elemente NgIf, NgFor und NgSwitch. Diese Direktiven ermöglichen es, Inhalte bedingt anzuzeigen, zu verbergen oder zu wiederholen. Auf den ersten Blick mag dies unkompliziert wirken, doch eine Überarbeitung der ursprünglichen Konzepte war notwendig, um Unklarheiten zu vermeiden. Seit Angular 18 stehen nun modifizierte Direktiven zur Verfügung, welche insbesondere eine Anpassung der Syntax beinhalten. In diesem Artikel möchte ich die überarbeitete Syntax anhand einfacher Beispiele vorstellen und die damit verbundenen Vorteile erläutern. Eine offizielle Dokumentation ist here zu finden. 

1. @if

Die ursprünglichen NgIf-Direktive basieren auf einem simplen Prinzip: Sobald die erforderliche Bedingung erfüllt ist, wird das Element angezeigt.

				
					@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   <div *ngif=condition></div>
 `,
 imports: [NgIf]
})
export class App {}


				
			

Das Einbauen eines Else-Zweigs schaffte Verwirrung: 

				
					@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   <div *ngif="condition; else falseMessage"></div>
   ... some other html content of the page ...
   <ng-template #falsemessage>...</ng-template>
 `,
 imports: [NgIf],
})
export class App {}

				
			

Die Syntax unterschied sich stark von der If-Else-Syntax aus TypeScript, was die Zugänglichkeit erschwerte und zu Unklarheiten führte. Eine Anpassung der Direktive sorgte für ein höheres Maß an Übersicht und Sauberkeit. Die überarbeitete Syntax: 

				
					@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   @if(condition) {
     <div>Content</div>
   } @else {
     <div>False Message</div>
   }
 `,
 imports: [NgIf],
})
export class App {}
				
			

2. @for

Die Anpassung der NgFor-Syntax brachte weniger Veränderungen mit sich. Ein wesentlicher Punkt ist jedoch folgender: Größere Datenmengen resultieren häufig in Performance-Problemen, da das Attribut trackBy leicht zu übersehen war. Die ursprüngliche Syntax:

				
					@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   <div *ngfor="let item of items">
    ...
   </div>
 `,
 imports: [NgFor],
})
export class App {
 items: any[] = [];
}
				
			

Das Angular-Team entschied sich hierbei für eine einfache Lösung: In der angepassten Version wurde das Attribut track verpflichtend gemacht. Ein weiterer überarbeiteter Punkt betraf die Möglichkeit, die Liste ohne zusätzlicher NgIf-Kontrolle auf Leerheit zu prüfen. Außerdem wurden für den NgFor-Block mehrere neue Kontext-Variablen eingeführt, wie beispielsweise $first oder $last. Die vollständige Liste ist here zu finden. Die überarbeitete Syntax:

				
					@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   @for (item of items; track item.id) {
     <div></div>
   } @empty {
     List is empty
   }
 `,
 imports: [NgFor],
})
export class App {
 items: any[] = [];
}

				
			

3. @switch

Grundsätzlich war das ursprüngliche Konzept der drei Direktiven NgSwitch, NgSwitchCase und NgSwitchDefault leicht verständlich und einfach anzuwenden. Die ursprüngliche Syntax:

				
					type State = 'PENDING' | 'IN_PROGESS' | 'DONE';

@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   <div [ngswitch]="currentState">
     <ng-container *ngswitchcase="'PENDING'">Pending</ng-container>
     <ng-container *ngswitchcase="'IN_PROGRESS'">Progress</ng-container>
     <ng-container *ngswitchcase="'DONE'">Done</ng-container>
     <ng-container *ngswitchdefault>No State</ng-container>
   </div>
 `,
 imports: [NgSwitch, NgSwitchCase, NgSwitchDefault],
})
export class App {
 currentState!: State;
}


				
			

Die Überarbeitung der Syntax sorgte jedoch für ein erhöhtes Maß an Lesbarkeit und orientierte sich stärker an der bekannten Syntax aus TypeScript. Die überarbeitete Syntax:

				
					type State = 'PENDING' | 'IN_PROGESS' | 'DONE';

@Component({
 selector: 'app-root',
 standalone: true,
 template: `
     @switch (currentState) {
       @case ('PENDING') {
         Pending
       }
       @case ('IN_PROGESS') {
         In Progress
       }
       @case ('DONE') {
         Done
       }
       @default {
         No state
       }
     }
 `,
 imports: [NgSwitch, NgSwitchCase, NgSwitchDefault],
})
export class App {
 currentState: State = 'PENDING';
}


				
			

Migration und Rückwärtskompatibilität

Angular bietet die Möglichkeit, die veralteten Direktive mit folgendem Befehl zu migrieren:

ng g @angular/core:control-flow

Wer jedoch weiterhin die gewohnte Syntax verwenden möchte, muss nicht darauf verzichten. Zur Sicherstellung der Rückwärtskompatibilität können die ursprünglichen Direktiven weiterhin genutzt werden und sollen voraussichtlich auch in den kommenden Versionen unterstützt werden.

Zusammenfassung

Die neuen Control-Flow-Elemente in Angular steigern die Lesbarkeit des Codebases, verfeinern dessen Struktur und reduzieren die Notwendigkeit von überflüssigem Boilerplate-Code. Zudem sorgen sie für eine intuitive Syntax und eine bessere Wartbarkeit.

Virtuelle Threads in Java 21

Virtuelle Threads in Java: Ein Paradigmenwechsel in der Concurrent Programmierung   Einführung in Virtuelle Threads Mit der Einführung von virtuellen Threads in Java (auch als

Weiterlesen »