La versión 17 de Angular ya está con nosotros y nos trae una nueva sintaxis llamada @-syntax que mejorar la experiencia de los desarrolladores con el framework. Esta nueva forma de redactar las templates viene a reemplazar los tradicionales *ngIf, *ngFor, *ngSwitch
y olvidarnos de los elementos <ng-template>
y <ng-container>
en nuestras aplicaciones.
Promete simplificar y modernizar la forma en la que trabajamos con Angular e incluso mejorar el rendimiento de nuestra aplicación. Aún así tengamos en cuenta que se encuentra en “Developer Preview”.
Ventajas
La nueva @-syntax propone importantes beneficios a tener en cuenta:
- Mejoras en la Legibilidad: La sintaxis es más declarativa haciendo más facil de entender la lógica del template para los desarrolladores.
- Mejora en la eficiencia: Disminuye la cantidad de boilerplate y aprovecha el nuevo sistema de detección de cambios.
- Soporte para lazy components (
@defer
): Esta nueva adición permite renderizar componentes bajo condiciones especificas.
Estrucutra condicional @if
Comúnmente para renderizar condicionalmente un componente u otro en el DOM utilizaríamos la directiva *ngIf
. El nuevo @if
aprovecha el nuevo sistema de detección de cambios basado en signals para lograr el mismo propósito.
@if (show) {
<span>Inside if</span>
} @else if (showAnotherIf) {
<span>Inside else if</span>
} @else {
<span>Inside else</span>
}
<ng-container *ngIf="show; else elseTemplate">
<span>Inside if</span>
</ng-container>
<ng-template #elseTemplate>
<ng-container *ngIf="show; else anotherElseTemplate">
<span>Inside else if</span>
</ng-container>
<ng-template #anotherElseTemplate>
<span>Inside else</span>
</ng-template>
</ng-template>
@Component({
selector: "some-component",
standalone: true,
imports: [CommonModule, RouterOutlet],
templateUrl: "./some.component.html",
styleUrls: ["./some.component.scss"],
})
export class SomeComponent {
show = true;
showAnotherIf = false;
}
Esta nueva sintaxis ,al clumplitse la condición, muestra el contenido entre llaves, de lo contrario muestra lo que se encuentra dentro del @else
o distintos @else if ()
.
La nueva sintaxis es más concisa, legible e igual o más flexible que antes. Por otro lado evitamos el uso de <ng-template>
y <ng-container>
que, muchas veces, no son tan utilizados por los desarrolladores.
Estrucutra repetitiva @for
La estructura @for
reemplaza a la directiva *ngFor
, permitiendonos renderizar contenido de un arrelgo o iterable. También provee de un nuevo bloque, definido como @empty
, que será renderizado en caso de que la lista esté vacía.
<ul>
@for (user of userList; track user.id; let i = $index){
<li>{{ i }}. {{ user.name }}</li>
} @empty {
<li>Empty array</li>
}
</ul>
<ul>
<ng-container *ngIf="userList.length; else emptyArray">
<li *ngFor="let user of userList; index as i">{{i}}. {{ user.name }}</li>
</ng-container>
<ng-template #emptyArray>
<li>Empty array</li>
</ng-template>
</ul>
@Component({
selector: "some-component",
standalone: true,
imports: [CommonModule, RouterOutlet],
templateUrl: "./some.component.html",
styleUrls: ["./some.component.scss"],
})
export class SomeComponent {
userList = [
{ name: "Jhon", id: 1 },
{ name: "Steve", id: 2 },
{ name: "Alex", id: 3 },
];
}
El bloque @empty
nos facilita renderizar un elemento especial en caso de que el iterable esté vacío sin la necesidad de agregar un *ngIf
.
Un punto destacado a mencionar es que ahora track
es requerido, en este debemos usar id o cualquier otro identificador único. Se mantienen las variables implícitas de la estructura como: $index, $first, $last, $even, $odd
Estrucutra de control @switch
El bloque @switch
toma el lugar de *ngSwitch
, la forma de escribir esta estrucura brinda una clara mejora en la legibilidad y elimina la necesidad de contenedores extra para mantener las expresiones de cada condición.
@switch (page) {
@case (1) {
<p>Viewing content of first page</p>
}
@case (2) {
<p>Viewing content of second page</p>
}
@case (3) {
<p>Viewing content of third page</p>
}
@default {
<p>No page selected</p>
}
}
<ng-container [ngSwitch]="page">
<ng-container *ngSwitchCase="1">
<p>Viewing content of first page</p>
</ng-container>
<ng-container *ngSwitchCase="2">
<p>Viewing content of second page</p>
</ng-container>
<ng-container *ngSwitchCase="3">
<p>Viewing content of third page</p>
</ng-container>
<ng-container *ngSwitchDefault>
<p>No page selected</p>
</ng-container>
</ng-container>
@Component({
selector: "some-component",
standalone: true,
imports: [CommonModule, RouterOutlet],
templateUrl: "./some.component.html",
styleUrls: ["./some.component.scss"],
})
export class SomeComponent {
page = 2;
}
Notas importantes
Por último hay unos puntos importantes a saber con el lanzamiento de Angular 17:
- Las directivas
*ngIf
,*ngFor
,*ngSwitch
y los elementos<ng-template>
y<ng-container>
no están deprecados, siguen siendo soportados por la nueva actualización. - Ambas sintaxis son compatibles entre ellas, es decir, se pueden usar ambas simultaneamente.
- No es solo una nueva sintaxis, sino que trae mejoras en rendimiento, entre un 30% y 90%.
- Hay otro bloque nuevo introducido del que no hice mención llamado
@defer
. - Existe un comando de Angular CLI que ejecuta la migración automáticamente
ng g @angular/core:control-flow
Las últimas actualizaciones de Angular están cambiando las reglas de juego tradicionales de este framework brindando mejoras significativas y mejorarndo la calidad de desarrollo.
En lo personal, comenzar un proyecto desde cero en las nuevas versiones de Angular con standalone y @-syntax, se siente distinto 🚀. El nuevo control flow sencillamente me encanta y le da un toque fresco al framework.
Ahora solo queda por hacer un ng update
.