Section 11.1.14 : JavaScript — Événements et Fetch API
🎯 Objectif pédagogique
Maîtriser le système d'événements JavaScript pour gérer les interactions utilisateur, et utiliser l'API Fetch pour communiquer avec des serveurs distants. Vous serez capable de créer des interfaces réactives et de consommer des données depuis des APIs.
Les événements — Écouter l'utilisateur
Chaque action de l'utilisateur (clic, frappe, scroll, survol) génère un événement. JavaScript permet d'écouter ces événements et de réagir.
const button = document.querySelector("#my-button");
// Méthode recommandée : addEventListener
button.addEventListener("click", (event) => \{
console.log("Bouton cliqué !");
console.log("Position X :", event.clientX);
console.log("Élément cliqué :", event.target);
\});
Événements courants
| Événement | Déclencheur | Exemple |
|---|---|---|
click | Clic souris | Bouton, lien, carte |
dblclick | Double-clic | Édition en ligne |
keydown / keyup | Touche enfoncée/relâchée | Raccourcis clavier |
input | Frappe dans un champ | Recherche en temps réel |
submit | Soumission de formulaire | Envoi de données |
change | Changement de valeur | Select, checkbox |
mouseover / mouseout | Survol / Quitte | Tooltips, previews |
scroll | Défilement | Lazy loading, animations |
load | Page complètement chargée | Initialisation |
DOMContentLoaded | HTML parsé (avant images) | Setup initial |
event.preventDefault() — Contrôler le comportement
// Empêcher un formulaire de recharger la page
const form = document.querySelector("form");
form.addEventListener("submit", (event) => \{
event.preventDefault(); // Empêche le rechargement
const name = form.querySelector("#name").value;
const email = form.querySelector("#email").value;
console.log("Données :", \{ name, email \});
// Envoyer via Fetch au lieu du rechargement
\});
// Empêcher un lien de naviguer
const link = document.querySelector(".custom-link");
link.addEventListener("click", (event) => \{
event.preventDefault();
console.log("Lien intercepté !");
\});
Event Delegation — Efficacité maximale
Plutôt que d'attacher un événement à chaque carte, attachez-le au conteneur parent :
// ❌ Éviter : un listener par élément
document.querySelectorAll(".card").forEach(card => \{
card.addEventListener("click", () => \{ /* ... */ \});
\});
// ✅ Meilleur : un seul listener sur le parent
document.querySelector(".cards-grid").addEventListener("click", (event) => \{
const card = event.target.closest(".card");
if (card) \{
console.log("Carte cliquée :", card.dataset.id);
\}
\});
Fetch API — Communiquer avec un serveur
// GET — Récupérer des données
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await response.json();
console.log(users);
// Avec gestion d'erreur
async function fetchUsers() \{
try \{
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) \{
throw new Error(\`HTTP \$\{response.status\}\`);
\}
const users = await response.json();
return users;
\} catch (error) \{
console.error("Erreur :", error.message);
return [];
\}
\}
POST — Envoyer des données
async function createUser(userData) \{
try \{
const response = await fetch("https://jsonplaceholder.typicode.com/users", \{
method: "POST",
headers: \{
"Content-Type": "application/json"
\},
body: JSON.stringify(userData)
\});
const newUser = await response.json();
console.log("Utilisateur créé :", newUser);
return newUser;
\} catch (error) \{
console.error("Erreur :", error.message);
\}
\}
// Utilisation
createUser(\{ name: "Marc Dupont", email: "marc@email.com" \});
Exemple complet : recherche d'utilisateurs
<input type="text" id="search" placeholder="Rechercher un utilisateur...">
<div id="results"></div>
const searchInput = document.querySelector("#search");
const resultsDiv = document.querySelector("#results");
// Debounce : attendre que l'utilisateur arrête de taper
let timeout;
searchInput.addEventListener("input", () => \{
clearTimeout(timeout);
timeout = setTimeout(async () => \{
const query = searchInput.value.trim();
if (query.length < 2) \{
resultsDiv.innerHTML = "";
return;
\}
const users = await fetchUsers();
const filtered = users.filter(u =>
u.name.toLowerCase().includes(query.toLowerCase())
);
resultsDiv.innerHTML = filtered.map(u => \`
<div class="user-card">
<strong>\$\{u.name\}</strong>
<p>\$\{u.email\}</p>
</div>
\`).join("");
\}, 300); // 300ms après la dernière frappe
\});
🏋️ Exercice pratique (25 minutes)
Créez une mini-app météo :
// 1. Formulaire de recherche de ville
const form = document.querySelector("#weather-form");
const cityInput = document.querySelector("#city");
const weatherDiv = document.querySelector("#weather-result");
form.addEventListener("submit", async (event) => \{
event.preventDefault();
const city = cityInput.value.trim();
if (!city) return;
weatherDiv.textContent = "Chargement...";
try \{
// API gratuite sans clé
const response = await fetch(
\`https://wttr.in/\$\{encodeURIComponent(city)\}?format=j1\`
);
const data = await response.json();
const current = data.current_condition[0];
weatherDiv.innerHTML = \`
<h3>Météo à \$\{city\}</h3>
<p>🌡️ Température : \$\{current.temp_C\}°C</p>
<p>💧 Humidité : \$\{current.humidity\}%</p>
<p>🌤️ \$\{current.weatherDesc[0].value\}</p>
\`;
\} catch (error) \{
weatherDiv.textContent = "Erreur — ville introuvable";
\}
\});
Marc : "fetch + async/await = la base de toute application web moderne. Les données ne sont pas statiques — elles viennent d'APIs."
Pourquoi utiliser event.preventDefault() sur un formulaire ?
Que signifie le mot-clé 'await' devant fetch() ?
Qu'est-ce que l'Event Delegation ?