Solutions niveau 5 contact (filet de securite, a consulter en dernier recours) + FAQ erreurs frequentes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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 <td> 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 <tr> cliquée, peu importe la <td>
|
||||
if (ligne) {
|
||||
alert("Membre : " + ligne.dataset.nom);
|
||||
}
|
||||
});
|
||||
```
|
||||
> 💬 *« Pourquoi ne pas mettre l'écouteur sur chaque `<tr>` ? »* 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 `<td>` ; `closest` remonte jusqu'à la `<tr>` 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
|
||||
<script type="module" src="../contact.js"></script>
|
||||
```
|
||||
> 💬 *« 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.
|
||||
Reference in New Issue
Block a user