Aller au contenu
← 1001 Widgets
N° 006 · ●○○

Liste de tâches

Une liste de tâches : ajouter, cocher, supprimer. Le classique qui oblige à séparer les données de l'affichage.

HTMLJS
Ce qu'on apprend
  • Garder les tâches dans un tableau d'objets
  • Redessiner la liste à partir des données
  • Écouter tous les clics avec un seul écouteur
Pourquoi ce langage

Pourquoi une liste de tâches ? C'est le premier vrai petit logiciel : on ajoute, on coche, on supprime. Une grande partie du web n'est qu'une variation de ces trois gestes.

La règle d'or : les données d'abord. On garde un tableau de tâches, et on redessine la liste à partir de lui. Jamais l'inverse.

Pourquoi en JavaScript simple ? Un tableau, une fonction d'affichage, deux écouteurs. On voit exactement ce que React fera plus tard à votre place.

Comment ça marche
  1. LE HTML

    Un formulaire pour ajouter, une liste vide que le script remplit.

    <form id="ajout">
      <input id="texte" placeholder="Nouvelle tâche" required>
      <button>Ajouter</button>
    </form>
    <ul id="liste"></ul>
  2. L'ÉTAT

    Une seule source de vérité : le tableau. La page n'en est que le reflet.

    let taches = [];
  3. AFFICHER

    On vide la liste et on la reconstruit depuis le tableau. textContent protège des balises tapées par l'utilisateur.

    function afficher() {
      const ul = document.getElementById('liste');
      ul.innerHTML = '';
      taches.forEach(t => {
        const li = document.createElement('li');
        li.dataset.id = t.id;
        li.innerHTML = '<label><input type="checkbox"><span></span></label><button>Supprimer</button>';
        li.querySelector('span').textContent = t.texte;
        li.querySelector('input').checked = t.faite;
        ul.append(li);
      });
    }
  4. AJOUTER

    preventDefault empêche le formulaire de recharger la page.

    document.getElementById('ajout').addEventListener('submit', e => {
      e.preventDefault();
      const champ = document.getElementById('texte');
      taches.push({ id: Date.now(), texte: champ.value.trim(), faite: false });
      champ.value = '';
      afficher();
    });
  5. COCHER ET SUPPRIMER

    Un seul écouteur sur la liste suffit : c'est la délégation d'événements.

    document.getElementById('liste').addEventListener('click', e => {
      const li = e.target.closest('li');
      if (!li) return;
      const id = Number(li.dataset.id);
      if (e.target.matches('input')) {
        taches = taches.map(t => t.id === id ? { ...t, faite: !t.faite } : t);
        afficher();
      } else if (e.target.matches('button')) {
        taches = taches.filter(t => t.id !== id);
        afficher();
      }
    });
Pièges

PIÈGE 1 : Injecter le texte avec innerHTML

Piège

Mauvais : li.innerHTML = t.texte. Une tâche nommée <img src=x onerror=alert(1)> exécute du code dans la page.

Fix

Correct : textContent pour tout ce qui vient de l'utilisateur.

PIÈGE 2 : Un écouteur par tâche

Piège

Mauvais : un addEventListener sur chaque case, à chaque affichage. Ils s'empilent et la mémoire grossit.

Fix

Correct : un seul écouteur sur la liste, et e.target pour savoir où on a cliqué.

PIÈGE 3 : Modifier la page au lieu des données

Piège

Mauvais : barrer le texte directement dans le DOM. Au prochain affichage, la modification disparaît.

Fix

Correct : changer le tableau, puis appeler afficher().

PERSONNALISER
  • Un compteur « 3 tâches restantes » avec taches.filter(t => !t.faite).length.
  • Trois filtres, Toutes, À faire et Faites, appliqués juste avant l'affichage.
  • Un double clic sur une tâche qui la transforme en champ texte pour la renommer.
OPTIMISATION
  • Pour des centaines de tâches, ne recréez que la ligne qui change au lieu de toute la liste.
  • Rangez le tableau dans localStorage à chaque modification : c'est la variante « Liste de tâches qui se souvient ».
VERS REACT

taches devient un useState, et afficher() disparaît : React redessine tout seul.

Chaque <li> reçoit key={t.id}, jamais l'index du tableau.

On ne modifie jamais le tableau : on en crée un nouveau avec map et filter, exactement comme ici.

Variantes
Commentaires
0/1000

Chargement des commentaires…