Angular 17 donosi mnoštvo novina među kojima je ugrađena kontrola toka (built-in control flow) u okviru template-a (šablona) komponenata.
Pod kontrolom toka u okviru template-a se tipično misli na ponavljanje ili uslovni prikaz HTML elemenata ili grupe elemenata. Za ovo su do verzije 17 bile namenjene tzv. strukturalne direktive (one koje menjaju strukturu DOM stabla), konkretno *ngFor, *ngIf i [ngSwitch].
Često korišćeni način za izražavanje direktiva u raznim template procesorima, pa i u slučaju Angular template-a je njihovo navođenje u otvarajućim tag-ovima HTML elemenata i to u vidu custom (posebnih) atributa koji nisu deo HTML specifikacije. Za vreme prikaza (rendering) sadržaja, template procesor prepoznaje i izvršava direktive, a u prikazu ostaje samo rezultat izvršavanja direktiva.
Zapis direktiva na ovaj način dozvoljava njihovo izražavanje upotrebom već postojeće HTML sintakse (atributi, iako custom, su i dalje atributi), odnosno izbegava modifikacije u HTML parser-u (delu programa koji analizira, validira i raščlanjuje sintaksu).
Izražavanje strukturalnih direktiva na ovaj način je često neintuitivno, pa su se autori verzije Angular 17 ipak opredili za konkretniju sintaksu, značajno bližu TypeScript jeziku, uz napomenu da su pomenute tradicionalne direktive i dalje podržane.
@for blok
<table>
<thead>
<tr><th>#</th><th>Name</th><th>Price</th></tr>
</thead>
<tbody>
<tr *ngFor=“let itProduct of products; let it = index”>
<td>{{it + 1}}</td>
<td>{{itProduct.name}}</td>
<td>{{itProduct.price}}</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr><th>#</th><th>Name</th><th>Price</th></tr>
</thead>
<tbody>
@for (itProduct of products; let it = $index; track it) {
<tr>
<td>{{it + 1}}</td>
<td>{{itProduct.name}}</td>
<td>{{itProduct.price}}</td>
</tr>
}
</tbody>
</table>
Slika 1. @for blok
Na slici 1 se može uočiti da @for blok više nije izražen u delu sadržaja koji se ponavlja. I dalje su podržane kontekstne promenljive poput $index (redni broj iteracije), $count (ukupan broj iteracija), i sl. Neophodan je međutim track izraz u zaglavlju koji ukazuje na bilo kakav jedinstveni podatak u tekućoj iteraciji, koji može biti sadržan u indeksu petlje, npr. itProduct.id ili može kao u primeru sa slike biti redni broj iteracije. Ovaj podatak Angular koristi za efikasnije interno “knjigovođstvo“ sadržaja definisanog unutar bloka.
@if, @else if, @else blok
<ng-container *ngIf=“date.getHours() >= 5 && date.getHours() < 12; else notMorning”>
<p>It’s morning!</p>
</ng-container>
<ng-template #notMorning>
<ng-container *ngIf=“date.getHours() >= 12 && date.getHours() < 17; else notAfternoon”>
<p>It’s afternoon!</p>
</ng-container>
</ng-template>
<ng-template #notAfternoon>
<ng-container *ngIf=“date.getHours() >= 17 && date.getHours() < 21; else notEvening”>
<p>It’s evening!</p>
</ng-container>
</ng-template>
<ng-template #notEvening>
<p>It’s night!</p>
</ng-template>
@if (date.getHours() >= 5 && date.getHours() < 12) {
<p>It’s morning!</p>
} @else if (date.getHours() >= 12 && date.getHours() < 17) {
<p>It’s afternoon!</p>
} @else if (date.getHours() >= 17 && date.getHours() < 21) {
<p>It’s evening!</p>
} @else {
<p>It’s night!</p>
}
Slika 2. @if, @else if, @else blok
Na primeru *ngIf direktive sa slike 2 su značajno izraženi njeni nedostaci u odnosu na novu alternativu. Da bi se postigla if-else-if-else funkcionalnost neophodna je bila upotreba ne samo *ngIf direktive, već i ng-container i ng-template elemenata kao i dodatnih template promenljivih.
@if, @else if i @else blokovi omogućuju tradicionalno kombinovanje uslovnih naredbi kakvo je podržano i TypeScript jezikom uz značajno manje boilerplate koda.
@switch blok
<table>
<tbody>
<tr>
<th>Currency</th>
<td [ngSwitch]=“transaction.currency”>
<span *ngSwitchCase=“‘USD'”>United States dollar</span>
<span *ngSwitchCase=“‘EUR'”>Euro</span>
<span *ngSwitchDefault>unknown</span>
</td>
</tr>
<tr><th>Amount</th><td>{{transaction.amount}}</td></tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<th>Currency</th>
<td>
@switch (transaction.currency) {
@case (“USD”) { United States dollar }
@case (“EUR”) { Euro }
@default { unknown }
}
</td>
</tr>
<tr><th>Amount</th><td>{{transaction.amount}}</td></tr>
</tbody>
</table>
Slika 3. @switch blok
Na primeru [ngSwitch] direktive sa slike 3 se najbolje vidi jedna od glavnih prednosti novih direktiva – nije potrebno da postoje kontejnerski elementi za izražavanje logike. Drugim rečima nije potreban poseban element u okviru kog bi se navodilo zaglavlje bloka, niti njegovi podelementi u kojima bi se navodili pojedinačni iskazi unutar bloka.
Angular control flow blokovi, pored uočenih, donose i sledeće prednosti:
- strožija provera tipova, pa samim tim smanjena mougćnost grešaka
- smanjenje obima izvršne verzije aplikacije
- značajno bolja performansa
Više detalja možete naći u zvaničnoj dokumentaciji:
https://angular.io/guide/control_flow
Ovu temu i još mnogo više u vezi Front-end razvoja, možete saznati i naučiti upisom na naš kurs Front-End Development.