From 438e567b31057c20693e4ea5ad45d1aed1b00645 Mon Sep 17 00:00:00 2001 From: matthieureynier Date: Mon, 22 Jun 2026 09:43:39 +0200 Subject: [PATCH] Solutions niveau 5 contact (filet de securite, a consulter en dernier recours) + FAQ erreurs frequentes Co-Authored-By: Claude Opus 4.8 (1M context) --- SOLUTIONS_contact_4.md | 165 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 SOLUTIONS_contact_4.md diff --git a/SOLUTIONS_contact_4.md b/SOLUTIONS_contact_4.md new file mode 100644 index 0000000..1bf9e8b --- /dev/null +++ b/SOLUTIONS_contact_4.md @@ -0,0 +1,165 @@ +# ✅ 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.