Aller au contenu principal

6-5 Directives (@for et @if)

Le composant ProjetsListe est quelque peu inutile dans sa forme actuelle et ne fait qu'afficher le texte projets-liste works!.

Et si on essayait d'afficher une liste de projets?

Nous n'avons pas encore intégré le concept de faire des appels d'API, donc nous commencerons en codant en dure une liste de projets dans le composant.

Créer une propriété pour contenir les projets

Dans ProjetsListe, ajoutez une propriété projets de type string[]. Notre liste de projets sera pour l'instant une simple liste de string.

src/app/projets-liste.ts
@Component({
selector: 'app-projets-liste',
imports: [],
template: `
<p>
projets-liste works!
</p>
`,
styles: ``
})
export class ProjetsListe {
protected projets: string[] = [
"Discreddit",
"Organisation du Lan Party",
"Organisation de la soirée jeu vidéo",
]
}
info

Un composant est une classe! Ainsi, en TypeScript on peut définir une nouvelle propriété et l'initialiser dans la classe.

On crée une propriété en la nommant (ex.: projets), deux points (:), suivi du type (un tableau de string ici string[]).

De plus, on utilise protected puisque cette propriété est pertinente à la classe elle-même, mais aussi au template HTML, sans toutefois vouloir l'exposer aux autres classes.

Faire de cette propriété un signal? Arf 😕

Pour l'instant, afin de garder les choses simples, nous ne ferons pas du array un signal comme pour la propriété title du composant App. C'est que pour des propriétés autre que de simples string ou number, la façon de mettre à jour un signal devient un peu plus complexe.

À cette étape-ci, trop complexe pour ce que nous avons besoin de faire!

Angular détectera quand même les changements, c'est seulement que ce sera moins performant. Et pour le niveau de complexité de notre app... ça ne paraitra pas!

Afficher la liste à l'aide d'une boucle (directive @for)

Mais comment passer d'un tableau dans le composant à afficher la liste dans la portion template de ce dernier.

Pour ce faire, on peut utiliser les directives.

Angular en propose plusieurs, mais parmi les plus populaires:

  • @if pour conditionnellement afficher un élément (équivalent de v-if en Vue)
  • @for pour répéter un élément en fonction d'éléments d'une liste (équivalent de v-for en Vue)
  • @switch pour afficher un élément parmi plusieurs possibilités en fonction d'une condition de type switch.

Nous aurons l'occasion d'explorer plus en détail certaines de ces directives plus tard, mais pour l'instant @for semble tout indiqué!

Syntaxe de @for

@for (item of items; track item.name) {
<li>{{ item.name }}</li>
} @empty {
<li>There are no items.</li>
}
info

La fonction track dans une boucle @for permet à Angular d'identifier de manière unique chaque élément de la liste. Elle indique à Angular comment "suivre" les éléments lors des mises à jour du DOM.

Dans le contexte d'un objet, on pourrait utiliser un identifiant unique (par exemple, id).

Pour une liste simple, on peut utiliser $index, soit l'index de l'élément dans le tableau.

Esssentiellement, avec track, Angular peut identifier quels éléments ont changé, été ajoutés ou supprimés, et ne met à jour que les parties nécessaires du DOM.

Utiliser @for pour la liste de projets

  1. Créez une liste ul vide pour commencer

    src/app/projets-liste.ts
    @Component({
    selector: 'app-projets-liste',
    imports: [],
    template: `
    <ul>
    </ul>
    `,
    styles: ``
    })
  2. Débutez une boucle @for

    src/app/projets-liste.ts
    @Component({
    selector: 'app-projets-liste',
    imports: [],
    template: `
    <ul>
    @for (projet of projets) {

    }
    </ul>
    `,
    styles: ``
    })
    attention

    Vous aurez une erreur comme quoi track est requis!

    La fonction track dans une boucle @for permet à Angular d'identifier de manière unique chaque élément de la liste. Elle indique à Angular comment "suivre" les éléments lors des mises à jour du DOM.

    Dans le contexte d'un objet, on pourrait utiliser un identifiant unique (par exemple, id).

    Pour une liste simple, ce qui est notre cas, on peut utiliser $index, soit l'index de l'élément dans le tableau.

    Esssentiellement, avec track, Angular peut identifier quels éléments ont changé, été ajoutés ou supprimés, et ne met à jour que les parties nécessaires du DOM.

  3. Utilisez $index avec track pour identifier chaque élément par son index dans le tableau.

    src/app/projets-liste.ts
    <ul>
    @for (projet of projets; track $index) {

    }
    </ul>
  4. Finalement, pour chaque itération de la boucle, on voudra afficher un <li> pour le projet

    src/app/projets-liste.ts
    @Component({
    selector: 'app-projets-liste',
    imports: [],
    template: `
    <ul>
    @for (projet of projets; track $index) {
    <li></li>
    }
    </ul>
    `,
    styles: ``
    })
  5. Observez dans votre navigateur le résultat

    http://localhost:4200
  6. Comme projet of projets expose une variable projet, il est maintenant possible d'utiliser le principe d'interpolation vue précédemment pour afficher le texte associé au projet!

    src/app/projets-liste.ts
    @Component({
    selector: 'app-projets-liste',
    imports: [],
    template: `
    <ul>
    @for (projet of projets; track $index) {
    <li>{{ projet }}</li>
    }
    </ul>
    `,
    styles: ``
    })
  7. Et maintenant dans votre navigateur:

    http://localhost:4200

Gérer un tableau vide avec @empty

La directive @for permet de lui ajouter @empty pour gérer le cas dans lequel le tableau serait vide. Cela est particulièrement utile pour afficher un message à l'utilisateur.

Par exemple, pour la liste de projets:

  1. Ajoutez la directive @empty à la suite de la boucle @for
    src/app/projets-liste.ts
    <ul>
    @for (projet of projets; track $index) {
    <li>{{ projet }}</li>
    } @empty {
    <li>Aucun projet</li>
    }
    </ul>
  2. Videz votre tableau de projets en mettant les projets en commentaire.
    export class ProjetsListe {
    protected projets: string[] = [
    /*"Discreddit",
    "Organisation du Lan Party",
    "Organisation de la soirée jeu vidéo",*/
    ];
    }
  3. Regardez le rendu sur la page d'accueil! 😊 img

Affichage conditionnel avec @if

Nous pouvons aussi gérer l'affichage conditionnel d'éléments à l'aide de la directive @if. En effet, @empty est très pratique, mais son désavantage principal est qu'il doit être directement lié à la boucle.

Cela veut dire que dans l'exemple précédent, le message "Aucun projet" doit obligatoirement être affiché dans un li puisque la boucle for est à l'intérieur d'un ul.

src/app/projets-liste.ts
<ul>
@for(projet of projets; track $index){
<li>{{ projet }}</li>
} @empty {
<li>Aucun projet</li>
}
</ul>

Il serait possible de plutôt utiliser @if pour carrément afficher la liste ou non.

info

@if est une directive de contrôle de flux qui permet d'afficher conditionnellement du contenu dans le template.

@if (condition) {
<div>Contenu affiché si la condition est vraie</div>
}
  1. Ajoutez une directive @if qui vérifie si la taille du tableau est supérieure à 0 pour afficher la liste.

    @if(projets.length > 0){
    <ul>
    @for (projet of projets; track $index) {
    <li>{{ projet }}</li>
    } @empty {
    <li>Aucun projet</li>
    }
    </ul>
    }
  2. Ajoutez une condition @else pour gérer le cas où la taille serait 0 et donc, le tableau vide.

    @if(projets.length > 0){
    <ul>
    @for (projet of projets; track $index) {
    <li>{{ projet }}</li>
    } @empty {
    <li>Aucun projet</li>
    }
    </ul>
    } @else {
    <p>Aucun projet</p>
    }
  3. Remarquez le résultat dans votre navigateur! img

    info

    Cela est visuellement mieux puisque nous ne voulons pas réellement afficher une liste lorsqu'il n'y a pas de projets, on veut simplement afficher un message.

Réafficher les projets

Parfait, nous sommes en mesure de gérer le cas où la liste est vide!

Pour la suite, assurez-vous d'afficher des projets et donc d'enlever le commentaire dans votre tableau:

export class ProjetsListe {
protected projets: string[] = [
"Discreddit",
"Organisation du Lan Party",
"Organisation de la soirée jeu vidéo",
];
}