Appearance
Ho, cette partie n'est plus d'actualité ! 👀
Depuis Angular 17, Utilisez les contrôles de flux comme @if
, @for
ou @switch
. C'est beaucoup plus simple et plus lisible. Pour en savoir plus, consultez Contrôles de flux.
Savoir utiliser la directive *ngFor
Préalablement: Ajoutons CommonModule
Pour utiliser le cette directive, vous devez d'abord inclure CommonModule
dans votre composant:
ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-mon-composant',
template: `
<!-- Mettez ici le template de votre composant -->
`,
standalone: true,
imports: [
CommonModule
],
})
export class MyComponent { }
Si vous mettez pas le module, vous aurez l'erreur suivante:
Can't bind to '<nom de la directive>' since it isn't a known property of 'div'
ngFor
est une directive importante pour votre application. Pourquoi ? Car vous recevez généralement des données de la part du serveur, et vous devez les afficher côté frontend :
js
import {Component} from '@angular/core';
@Component({
selector: 'app',
template: `
<p *ngFor="let user of users">{{user.name}} : {{user.age}}</p>
`
})
export class AppComponent {
users: any[] = [
{name: 'Sam', age: 45},
{name: 'Jim', age: 33},
{name: 'Ana', age: 17},
{name: 'Lou', age: 4},
]
}
Ici, nous avons un tableau d'utilisateurs (directement dans le code, mais nous pouvons imaginer que ces données seront récupérées sur un serveur par la suite).
La valeur de ngFor
reprend la syntaxe d'une boucle Javascript. La variable locale user
n'est utilisable que dans l'élément ayant ngFor
Utiliser d'autres variables locales
Il est parfois très utiliser de connaitre l'index, par exemple, pour afficher une numérotation à chaque tour de boucle. Il existe donc 5 variables locales :
index
: position de l'item. Commence à 0.first
: booléen indiquant si l'item est le premier de l'itérationlast
: booléen indiquant si l'item est le dernier de l'itérationeven
: booléen indiquant si la position de l'item est paireodd
: booléen indiquant si la position de l'item est impaire
Voici un code illustrant leur utilisation :
js
import {Component} from '@angular/core';
@Component({
selector: 'app',
styles: [
`
.red {
color: red;
}
`
],
template: `
<p *ngFor="let user of users ; let i = index ; let isEven = even" [ngClass]="{red: isEven}">
N°{{i}} --> {{user.name}} : {{user.age}}
</p>
`
})
export class AppComponent {
users: any[] = [
{name: 'Sam', age: 45},
{name: 'Jim', age: 33},
{name: 'Ana', age: 17},
{name: 'Lou', age: 4},
]
}
Les variables locales sont présentes dans ngFor
. Nous déclarons des nouvelles variables pour utiliser ces fameuses variables locales. Nous mixons notre boucle avec d'autres directives. Ici, lorsque l'index est pair alors l'élément est coloré en rouge.
Utiliser trackBy pour améliorer la performance
Nous allons utiliser un exemple pour se rendre compte de l'utilité de trackBy
.
js
import {Component} from '@angular/core';
@Component({
selector: 'app',
template: `
<p *ngFor="let user of users">
<user>
{{user.name}} : {{user.age}}
</user>
</p>
<button (click)="add()">Ajouter</button>
`
})
export class AppComponent {
users: any[] = [
{name: 'Sam', age: 45, id: 1},
{name: 'Jim', age: 33, id: 2},
{name: 'Ana', age: 17, id: 3},
{name: 'Lou', age: 4, id: 4},
];
add() {
let newIndex = this.users.length+1;
this.users = this.users.map((obj) => {
return Object.assign({}, obj);
})
this.users.push({name: `Test${newIndex}`, age: 15, id: newIndex});
}
}
Notre composant permet d'afficher les utilisateurs. Rien de nouveau. Nous avons ajouté un bouton ajoutant un nouvel utilisateur.
Le tableau users
a été cloné (en créant un objet immutable
). Le tableau n'étant plus le même que l'initial, Angular va supprimer tous les éléments dans le DOM et les récréer d'une manière itérative. Pour se rendre compte, nous avons créer un composant enfant :
js
import {Component} from '@angular/core';
@Component({
selector: 'user',
template: `
<ng-content></ng-content>
`
})
export class UserComponent {
ngOnInit() {
console.log('Utilisateur créé')
}
ngOnDestroy() {
console.log('Utilisateur supprimé')
}
}
Effectivement, qiand nous ajoutons un utilisateur, les logs sont appelés plusieurs fois : 4 suppressions et 5 créations ensuite. Imaginez la même chose mais avec 10000 utilisateurs...
Pour éviter cela, nous utilisons trackBy
qui mémorise les items selon une propriété unique. Très généralement, cette propriété est l'ID. Voici comment nous l'utilisons :
js
import {Component} from '@angular/core';
@Component({
selector: 'app',
template: `
<p *ngFor="let user of users ; trackBy: trackById">
<user>
{{user.name}} : {{user.age}}
</user>
</p>
<button (click)="add()">Ajouter</button>
`
})
export class AppComponent {
users: any[] = [
{name: 'Sam', age: 45, id: 1},
{name: 'Jim', age: 33, id: 2},
{name: 'Ana', age: 17, id: 3},
{name: 'Lou', age: 4, id: 4},
];
add() {
let newIndex = this.users.length+1;
// Create immutable object
this.users = this.users.map((obj) => {
return Object.assign({}, obj);
})
this.users.push({name: `Test${newIndex}`, age: 15, id: newIndex});
}
trackById(index: number, obj: any): number {
return obj.id;
}
}
Nous ajoutons donc trackBy
dans ngFor
avec la méthode à appeler (ici, trackById
). Cette dernière envoie l'identifiant de l'item.
Si vous testez et regardez les logs, vous remarquez que nous avons qu'une création lors d'un ajout d'un utilisateur. Bien mieux !