# ✅ 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.