Je wil dat jouw team efficiënt kan werken met technologieën die niet alleen nu, maar ook op lange termijn waarde leveren. Angular 18, uitgebracht in mei 2024, introduceert een belangrijke nieuwe feature die direct invloed heeft op de productiviteit en het beheer van jullie applicatie: de Control Flow API. Deze nieuwe template-syntax biedt aanzienlijke prestatieverbeteringen en maakt de code beter leesbaar en makkelijker te onderhouden. De overgang naar deze nieuwe aanpak is bovendien volledig backwards-compatible, waardoor je geen grote risico’s loopt in bestaande applicaties.
De vraag is: waarom zou jouw team dit moeten gebruiken? De Control Flow API optimaliseert de manier waarop condities in templates worden beheerd, met als resultaat een snellere, stabielere applicatie en een sterk vereenvoudigde codebase. Dit maakt toekomstige updates eenvoudiger, minimaliseert fouten en verhoogt de ontwikkelsnelheid. In deze blog ontdek je hoe jouw team deze functionaliteit kan toepassen en wat de concrete voordelen zijn voor zowel het ontwikkelproces als de prestaties van jullie applicaties.
Wat is Control Flow in Angular?
Control Flow is een nieuwe built-in feature van Angular die het mogelijk maakt aan de hand van condities blokken in je template te tonen, verbergen en iteratief te plaatsen. Is dit iets nieuws? Zeker niet! Angular kende deze functionaliteit al door het gebruik van *ngIf, *ngFor en *ngSwitch in je templates. Wat maakt deze wijziging dan zo interessant? De nieuwe syntax levert flinke prestatieverbeteringen, meer flexibiliteit en betere leesbaarheid van de templates. Een bijkomend voordeel van deze nieuwe functionaliteit is dat hij backwards-compatible is, waardoor je de control flow geleidelijk kunt toevoegen aan je applicatie, zonder direct de gehele applicatie te moeten aanpassen.
Wat is er precies verbeterd?
Voor het conditioneel tonen van blokken was voorheen altijd een element nodig in je template waarop een *ngIf geplaatst diende te worden. Voldoet de conditie niet? Dan gebruikte je een ng-template element om een alternatief blok te tonen. Wilde je iteratief over een aantal waardes uit een lijst lopen, maar in het geval van een lege lijst een melding tonen? Dan waren hiervoor meerdere checks nodig. Met de komst van control flow is dit niet langer nodig. Dit maakt het template een stuk beter leesbaar, maar verwijdert ook de noodzaak voor het gebruik van overbodige elementen. In de volgende code heb ik een winkelscenario ontwikkeld en wil ik aan de hand van condities een melding tonen aan de eindgebruiker. Is een gebruiker uitgelogd? Dan moet hij eerst inloggen, een mandje pakken en producten aan de winkelmand toevoegen.
<div class="app">
<div class="account-acties">
<h2>Account acties</h2>
<div class="account-acties-inhoud">
<button *ngIf="!ingelogd; else ingelogd" (click)="login()">Inloggen</button>
<ng-template #ingelogd>
<div *ngIf="winkelmand$ | async; else #geenWinkelmand">
<button (click)="addProductToBasket('Appel')">+ Appel</button>
<button (click)="addProductToBasket('Melk')">+ Melk</button>
<button (click)="addProductToBasket('Kaas')">+ Kaas</button>
</div>
<ng-template #geenWinkelmand>
<button (click)="takeBasket()">Pak een mandje</button>
</ng-template>
<button (click)="logout()">Uitloggen</button>
</ng-template>
</div>
</div>
<div class="winkelmand" *ngIf="ingelogd; else nogNietIngelogd">
<h2>Winkelmand</h2>
<div class="winkelmand-inhoud" *ngIf="(winkelmand$ | async) as winkelmand; else geenWinkelmand">
<p><b>Uw winkelmand:</b></p>
<ul>
<li *ngFor="let boodschap of winkelmand">{{boodschap}}</li>
<li *ngIf="winkelmand.length <= 0">Uw winkelmand is nog leeg.</li>
</ul>
</div>
<ng-template #geenWinkelmand>
<p>U heeft nog geen winkelmand.</p>
</ng-template>
</div>
<ng-template #nogNietIngelogd>
<p>U bent nog niet ingelogd. U kunt nog geen boodschappenmandje pakken.</p>
</ng-template>
</div>
Minpunten aan deze oude opzet zijn bijvoorbeeld dat er meerdere ng-template elementen nodig zijn voor het conditioneel tonen van meldingen. Ook de asynchrone data moet meerdere malen gebruikt worden, wat het template vult met veel code en de leesbaarheid niet ten goede komt. Met het gebruik van de nieuwe control flow ziet dit stuk code er heel anders uit. Hieronder is hetzelfde voorbeeld opgenomen, maar dan met het gebruik van de nieuwe syntax.
<div class="app">
//Eenmalig asynchrone data opslaan in een template variabele
@let winkelmand = (winkelmand$ | async);
<div class="account-acties">
<h2>Account acties</h2>
<div class="account-acties-inhoud">
@if (!ingelogd) {
<button (click)="login()">Inloggen</button>
} @else {
@if (!winkelmand) {
<button (click)="takeBasket()">Pak een mandje</button>
} @else {
<button (click)="addProductToBasket('Appel')">+ Appel</button>
<button (click)="addProductToBasket('Melk')">+ Melk</button>
<button (click)="addProductToBasket('Kaas')">+ Kaas</button>
}
<button (click)="logout()">Uitloggen</button>
}
</div>
</div>
@if (ingelogd) {
<div class="winkelmand">
<h2>Winkelmand</h2>
@if (winkelmand) {
<div class="winkelmand-inhoud">
<p><b>Uw winkelmand:</b></p>
<ul>
@for (boodschap of winkelmand; track boodschap) {
<li>{{boodschap}}</li>
} @empty {
<li>Uw winkelmand is nog leeg.</li>
}
</ul>
</div>
} @else {
// Er zijn geen ng-template elementen meer nodig.
<p>U heeft nog geen winkelmand.</p>
}
</div>
} @else {
<p>U bent nog niet ingelogd. U kunt nog geen boodschappenmandje pakken.</p>
}
</div>
Zoals je kunt zien, is het gebruik van ng-templates niet meer noodzakelijk, wat al wat overbodige code verhelpt. Deze elementen ogen verwarrend en komen de leesbaarheid van de code niet ten goede. Daarnaast zie je dat de for-loop een nieuwe optie kent: @empty. Is de variabele die jij in de loop wilt gebruiken nog leeg? Dan kun je dit blok hiervoor gebruiken. Voorheen was voor deze situatie een aanvullende *ngIf nodig. Daarnaast moet in deze loop nu aangegeven worden door middel van de “track”-optie op welke property uit de lijst Angular de elementen moet tracken. Hierdoor kan Angular nog beter met deze variabelen omgaan en dit verbetert de performance van de applicatie. Een andere mooie toevoeging in deze code is dat we met @let de asynchrone winkelmand eenmalig een alias kunnen geven en deze door het gehele template kunnen gebruiken. Hierdoor is de code enorm opgeschoond.
De nieuwe @switch directive biedt enkele verbeteringen ten opzichte van de traditionele *ngSwitch. Voorheen bestonden *ngSwitch en *ngSwitchCase al in Angular, maar de nieuwe @switch syntax maakt het mogelijk om condities eenvoudiger in te richten zonder gebruik van extra Angular directives en elementen. Dit maakt je templates nog leesbaarder en flexibeler. Een voorbeeld van hoe dit in de oude versie en in de nieuwe versie kan worden gebruikt, zal ik hieronder delen. We gebruiken weer een voorbeeld aan de hand van een winkel, namelijk over de aanwezigheid van een product. In de oude situatie zou dit er zo uitgezien hebben:
<ng-template [ngSwitch]="status">
<p *ngSwitchCase="'inStock'">Het product is op voorraad.</p>
<p *ngSwitchCase="'outOfStock'">Helaas, het product is uitverkocht.</p>
<p *ngSwitchCase="'discontinued'">Dit product wordt niet meer verkocht.</p>
<p *ngSwitchDefault>Status onbekend.</p>
</ng-template>
Met de nieuwe @switch directive, ziet dat er als volgt uit:
@switch (status) {
@case ('inStock') {
<p>Het product is op voorraad.</p>
}
@case ('outOfStock') {
<p>Helaas, het product is uitverkocht.</p>
}
@case ('discontinued') {
<p>Dit product wordt niet meer verkocht.</p>
}
@default {
<p>Status onbekend.</p>
}
}
Zoals je kunt zien, is de opzet in de control flow veranderd, waarbij de checks niet langer op de elementen zelf zitten, maar er omheen. Dit maakt de code beter leesbaar en ook hier is opnieuw een overbodig ng-element verdwenen.
Zelf aan de slag
Natuurlijk kun je nu als developer aan de slag om met de nieuwe control flow te werken, maar de Angular CLI biedt ook migraties om via de command line jouw applicatie naar de nieuwe control flow te migreren. Dit is dus snel en efficient en geeft direct performance-verbeteringen voor jouw applicatie. Wel is het altijd aangeraden om zelf na het draaien van de migratie de code te controleren. Om terug te komen op bijvoorbeeld de @switch, kun je eenvoudig gebruik maken van het volgende commando: ng generate @angular/core:control-flow
. Zelf de nieuwe control flow implementeren mag natuurlijk ook!
Conclusie
De nieuwe Control Flow API in Angular 18 biedt ontwikkelaars een efficiënte manier om condities in Angular-templates te beheren. Met de nieuwe, vereenvoudigde syntax, zoals @if, @let, en @switch, worden templates leesbaarder en overzichtelijker en kunnen overbodige elementen worden verwijderd. Daarnaast levert de nieuwe aanpak prestatieverbeteringen op, maar blijft backwards compatible zodat ook de oude syntax nog ondersteund wordt.
De toekomst van Angular ziet er veelbelovend uit. We zien steeds meer verbeteringen in performance en ontwikkelervaring. De komst van signals was een zo’n verbetering. Innovaties zoals de Control Flow API zorgen ervoor dat Angular relevant blijft in een snel veranderende wereld.
Wil je deze voordelen zelf ervaren? Probeer de nieuwe Control Flow-functionaliteit uit in jouw Angular-project en optimaliseer je applicaties met de nieuwste ontwikkelingen van Angular. Kom je er niet helemaal uit of wil je meer uitleg? Neem dan gerust contact op. Ik help je graag verder!
Extra Resources
Heb je vragen over dit onderwerp of zou je Sem willen inhuren voor een vergelijkbare opdracht?