La liaison foreach est l'un des outils les plus puissants de Knockout.js. Elle permet de parcourir un tableau et de dupliquer une section de balisage HTML pour chaque élément présent. C'est la solution idéale pour générer des listes, des tableaux ou tout élément répétitif au sein de votre interface utilisateur.
Lorsque vous utilisez un observableArray, Knockout gère intelligemment les mises à jour : si vous ajoutez, supprimez ou réorganisez des éléments, le DOM est mis à jour de manière chirurgicale sans recharger l'intégralité de la liste, garantissant ainsi des performances optimales.
Exemple fondamental : Rendu d'une liste simple
Dans cet exemple, nous générons un tableau de produits à partir d'un tableau d'objets JavaScript.
<table>
<thead>
<tr><th>Désignation</th><th>Prix</th></tr>
</thead>
<tbody data-bind="foreach: produits">
<tr>
<td data-bind="text: nom"></td>
<td data-bind="text: prix"></td>
</tr>
</tbody>
</table>
<script type="text/javascript">
ko.applyBindings({
produits: [
{ nom: 'Clavier Mécanique', prix: '85€' },
{ nom: 'Souris Sans Fil', prix: '40€' },
{ nom: 'Écran 27 pouces', prix: '250€' }
]
});
</script>
Interaction dynamique : Ajout et suppression
Voici comment gérer une liste de tâches interactive où l'utilisateur peut ajouter ou retirer des éléments en temps réel.
Vue (HTML) :
<h4>Gestionnaire de Tâches</h4>
<ul data-bind="foreach: listeTaches">
<li>
Index <span data-bind="text: $index"></span> :
<span data-bind="text: description"></span>
<button data-bind="click: $parent.supprimerTache">Retirer</button>
</li>
</ul>
<button data-bind="click: ajouterTache">Nouvelle tâche</button>
Modèle de vue (JavaScript) :
function TaskViewModel() {
var self = this;
self.listeTaches = ko.observableArray([
{ description: 'Réviser les observables' },
{ description: 'Configurer le projet' }
]);
self.ajouterTache = function() {
self.listeTaches.push({ description: 'Tâche créée à ' + new Date().toLocaleTimeString() });
};
self.supprimerTache = function(tache) {
self.listeTaches.remove(tache);
};
}
ko.applyBindings(new TaskViewModel());
Paramètres de la liaison
- Paramètre principal : Le tableau à itérer. Si c'est un
observableArray, la vue se synchronisera automatiquement. - Options étendues : Vous pouvez passer un objet contenant des propriétés telles que
data(le tableau),as(alias), ou des rappels (callbacks) commeafterAdd.
Propriétés de contexte spéciales
À l'intérieur d'une boucle foreach, vous avez accès à des variables de contexte utiles :
$data: Accède à l'élément actuel du tableau. Pratique si vous itérez sur un tableau de chaînes de caractères brutes.$index: Fournit l'index actuel (commençant à 0). C'est un observable qui se met à jour automatiquement si la liste change.$parent: Permet d'accéder aux données ou aux fonctions situées à l'extérieur de la boucle (le niveau hiérarchique supérieur).
Utilisation de l'alias avec "as"
Pour améliorer la lisibilité, surtout lors de boucles imbriquées, vous pouvez nommer l'élément courant :
<ul data-bind="foreach: { data: categories, as: 'cat' }">
<li>
<strong data-bind="text: cat.titre"></strong>
<ul data-bind="foreach: { data: articles, as: 'art' }">
<li>
<span data-bind="text: cat.titre"></span> : <span data-bind="text: art"></span>
</li>
</ul>
</li>
</ul>
Syntaxe sans conteneur (Éléments virtuels)
Il arrive que vous ne puissiez pas placer un data-bind sur un élément HTML existant (par exemple, à l'intérieur d'un <select> ou si vous ne voulez pas de balise parente supplémentaire). Utilisez alors les commentaires de liaison :
<ul>
<li>Début de liste</li>
<!-- ko foreach: items -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
Gestion des cycles de vie et animations
Knockout propose des hooks pour exécuter du code à des moments précis du rendu :
afterRender: Exécuté lors de l'insertion initiale ou de l'ajout d'un nouvel élément.afterAdd: Similaire à afterRender, mais déclenché uniquement lors de l'ajout de nouveaux éléments au tableau.beforeRemove: Appelé juste avant la suppression d'un élément du DOM. C'est ici que vous pouvez implémenter des effets de sortie (ex: fadeOut).
Exemple d'animation simple avec jQuery via afterAdd :
self.effetApparition = function(element) {
if (element.nodeType === 1) {
$(element).hide().fadeIn();
}
};
<div data-bind="foreach: { data: maListe, afterAdd: effetApparition }">
<div data-bind="text: $data"></div>
</div>