# ✅ Solutions — Niveau 5 contact (`PROCHAINE_ETAPE_contact_4.md`) > 🛑 **À NE REGARDER QU'EN DERNIER RECOURS.** > Cherche d'abord par toi-même (au moins 10–15 min, doc MDN à l'appui). Quand tu lis une réponse : lis-la, **ferme le fichier**, et réécris-la **de mémoire**. C'est comme ça que ça rentre. Le code ci-dessous est **un** exemple correct. Le tien peut être différent et tout aussi valable. --- ## 🧪 Exo 1 — `map` ```js const noms = equipe.map(function (membre) { return membre.nom; }); console.log(noms); // ["Mélissa", "Guillaume"] ``` > 💬 *« `map` ou `filter` ? »* `filter` garde/jette des éléments (la liste rétrécit). `map` transforme chaque élément (la liste garde la même taille). Ici on veut transformer chaque objet en son nom → `map`. --- ## 🧪 Exo 2 — `find` ```js const personne = equipe.find(function (membre) { return membre.partie === "Page contact"; }); if (personne) { console.log(personne.nom); } else { console.log("Personne ne correspond."); } ``` > 💬 *« Pourquoi le `if (personne)` ? »* Si aucun élément ne correspond, `find` renvoie `undefined`. Faire `personne.nom` planterait. On vérifie d'abord. (Variante moderne : `personne?.nom` — cherche `optional chaining`.) --- ## 🧪 Exo 3 — `reduce` Avec une boucle (plus lisible pour commencer) : ```js let totalKm = 0; for (const v of vehicules) { totalKm = totalKm + v.km; } ``` La même chose en `reduce` : ```js const totalKm = vehicules.reduce(function (somme, v) { return somme + v.km; }, 0); // ← 0 = la valeur de départ console.log(totalKm); ``` > 💬 *« À quoi sert le `0` à la fin ? »* C'est la valeur de départ de l'accumulateur (`somme`). Pour une somme on part de 0 ; pour multiplier on partirait de 1. --- ## 🧪 Exo 4 — Délégation d'événements Quand tu génères les lignes, marque chaque ligne avec le nom (un attribut `data-…`) : ```js function creerLigne(membre) { const tr = document.createElement("tr"); tr.dataset.nom = membre.nom; // devient data-nom="..." dans le HTML // ... (les comme avant) return tr; } ``` Puis **un seul** écouteur, sur le parent qui ne bouge pas : ```js const corps = document.getElementById("corps_equipe"); corps.addEventListener("click", function (event) { const ligne = event.target.closest("tr"); // la cliquée, peu importe la if (ligne) { alert("Membre : " + ligne.dataset.nom); } }); ``` > 💬 *« Pourquoi ne pas mettre l'écouteur sur chaque `` ? »* Parce que tes lignes sont recréées à chaque recherche/tri : il faudrait tout réattacher à chaque fois. En écoutant le **parent** (qui, lui, ne change pas), ça marche même pour les lignes créées plus tard. > 💬 *« À quoi sert `closest("tr")` ? »* Le clic peut tomber sur une `` ; `closest` remonte jusqu'à la `` qui la contient. --- ## 🧪 Exo 5 — Debounce sur la recherche ```js let minuteur; // garde la trace du minuteur en cours champRecherche.addEventListener("input", function () { clearTimeout(minuteur); // on annule le précédent minuteur = setTimeout(function () { // on en relance un const mot = champRecherche.value.toLowerCase(); const resultats = equipe.filter(m => m.nom.toLowerCase().includes(mot)); afficherEquipe(resultats); }, 300); // 300 ms après la DERNIÈRE frappe }); ``` > 💬 *« Comment ça « attend » ? »* À chaque frappe, on **annule** le minuteur précédent (`clearTimeout`) et on en repart un de 300 ms. Tant que tu tapes, il est sans cesse annulé ; il ne se déclenche que quand tu fais une pause. --- ## 🧪 Exo 6 — Modules `export` / `import` `navbar.js` : ```js export function creerNavbar(pageActive) { return `... ton HTML de navbar ...`; } ``` `contact.js` (tout en haut) : ```js import { creerNavbar } from "./navbar.js"; document.body.insertAdjacentHTML("afterbegin", creerNavbar("contact")); ``` HTML : ```html ``` > 💬 *« Depuis que j'utilise `type="module"`, mes autres scripts ne se voient plus ! »* Normal : chaque module a son **propre** espace. Une variable d'un fichier n'est plus visible ailleurs **sauf** si tu l'`export`es et l'`import`es. C'est justement le but : plus de variables globales qui se marchent dessus. > 💬 *« Erreur CORS au chargement du module. »* Comme `fetch`, les modules exigent un serveur : `python3 -m http.server` puis `http://localhost:8000/...` (pas `file://`). --- ## 🧪 Exo 7 — Vraie API en ligne ```js async function chargerUtilisateurs() { const liste = document.getElementById("liste_users"); try { const reponse = await fetch("https://jsonplaceholder.typicode.com/users"); const users = await reponse.json(); for (const u of users) { const li = document.createElement("li"); li.textContent = `${u.name} — ${u.email}`; liste.append(li); } } catch (erreur) { console.error(erreur); } } chargerUtilisateurs(); ``` > 💬 *« Comment je sais que les clés s'appellent `name` et `email` ? »* J'ai d'abord ouvert `https://jsonplaceholder.typicode.com/users` dans le navigateur pour **voir** la forme des données. Fais toujours ça avant d'afficher. > 💬 *« Ça marche sur le web mais mon fichier local non ? »* Une API en ligne autorise les requêtes externes (CORS) ; un fichier local ouvert en `file://` non. D'où le serveur local pour tes propres fichiers. --- ## 🧪 Exo 8 — `FormData` ```js formulaire.addEventListener("submit", function (evenement) { evenement.preventDefault(); const data = new FormData(formulaire); const valeurs = Object.fromEntries(data); console.log(valeurs); // { prenom: "...", email: "...", contacter: "..." } }); ``` > 💬 *« `FormData` me renvoie du vide ! »* Vérifie que chaque champ a un attribut **`name`** (pas seulement `id`). `FormData` lit les champs par leur `name`. > 💬 *« C'est mieux que `getElementById` partout ? »* Pour lire **tout** un formulaire d'un coup, oui : une ligne au lieu d'un `getElementById` par champ. Pour un seul champ ponctuel, `getElementById` reste très bien. --- ### 🆘 Encore bloquée après la solution ? Note : *ce que tu attendais, ce qui se passe à la place, et ce qu'affiche la Console (F12)*. Avec ces 3 infos, on débloque vite.