Plan d'enseignement - Cours 122
Vue d'ensemble des 15 séances
| Séance | Date | Module | Contenu | Exercices Nuxy |
|---|---|---|---|---|
| 1 ✓ | 21.01 | M1 | Bases JavaScript | 1.1 - 1.9 |
| 2 ✓ | 28.01 | M2 | Conditions | 2.1 - 2.6 |
| 3 ✓ | 04.02 | M3 | Boucles | 3.1 - 3.4 |
| 4 ✓ | 11.02 | M4 | Fonctions | 4.1 - 4.4 |
| 5 ✓ | 25.02 | M5 | Tableaux (bases) | 5.1 - 6.10 |
| 6 ✓ | 04.03 | M1-M7 | Démo CinéJS + Intro DOM | 7.1 - 7.7 |
| 7 ✓ | 11.03 | M7 | DOM | Terminer M7 |
| 8 ✓ | 25.03 | Projet | Présentation projet + validation ressource | 8.1 - 8.4 |
| 9 ✓ | 01.04 | Projet | Copilot + dépôt + données + premier affichage | 8.5 - 8.8 |
| 10 | 22.04 | Projet | Affichage dynamique (cartes) + CSS | Rattrapage |
| 11 | 29.04 | Projet | Tri et recherche | Rattrapage |
| 12 | 06.05 | Projet | Ajout et suppression | Tout terminé |
| 13 | 13.05 | Projet | Finalisation et responsive design | - |
| 14 | 20.05 | - | Révisions théoriques | - |
| 15 | 27.05 | - | EXAMEN BLANC | - |
Semaines sans cours
- 18 février (vacances)
- 18 mars (pas de cours)
- 8 et 15 avril (vacances de Pâques)
Séance 1 - 21 janvier 2026 ✓
Thème : Bases JavaScript
Objectifs :
- Comprendre ce qu'est JavaScript et son rôle
- Savoir utiliser la console du navigateur (DevTools)
- Déclarer des variables avec
letetconst - Connaître les types de données de base
- Effectuer des opérations et manipuler du texte
- Utiliser les méthodes
console
Ressources :
Devoirs Nuxy : Exercices 1.1 à 1.9 (tout le module 1)
Séance 2 - 28 janvier 2026 ✓
Thème : Conditions
Objectifs :
- Écrire des conditions avec
if,else if,else - Utiliser les opérateurs de comparaison (
===,!==,<,>) - Combiner des conditions avec
&&et|| - Gérer des cas multiples avec
switch/case - Utiliser l'opérateur ternaire
Ressources :
Devoirs Nuxy : Exercices 2.1 à 2.6
Séance 3 - 4 février 2026 ✓
Thème : Boucles
Objectifs :
- Kahoot "JavaScript les bases" - Lien pour s'entraîner seul
- Répéter des actions avec
while - Parcourir avec
foretfor...of - Comprendre
do...whileetbreak
Ressources :
Devoirs Nuxy : Exercices 3.1 à 3.4
Séance 4 - 11 février 2026 ✓
Thème : Fonctions
Objectifs :
- Déclarer et appeler des fonctions
- Passer des paramètres
- Retourner des valeurs avec
return - Utiliser la syntaxe arrow function
Ressources :
Devoirs Nuxy : Exercices 4.1 à 4.4
Séance 5 - 25 février 2026 ✓
Thème : Tableaux - Les bases
Objectifs :
- Créer et manipuler des tableaux
- Accéder aux éléments par index
- Modifier un tableau (
push,pop,shift,unshift) - Parcourir avec
forEach - Trier avec
sort()et filtrer avecfilter()
Ressources :
Devoirs Nuxy : Terminer les modules 5 et 6 complets (exercices 5.1 à 5.11, 6.1 à 6.10)
Important
Ces méthodes (filter, map, sort, reduce) seront réutilisées dans le projet final ! Les modules 5 et 6 doivent être terminés pour la séance 6.
Séance 6 - 4 mars 2026 ✓
Thème : Démo CinéJS - Synthèse M1-M6 + Introduction au DOM
Récupérer le projet CinéJS
Étape 1 — Créer votre copie du projet
- Ouvrir le dépôt template : github.com/fallinov/esig-122-demo-films
- Cliquer sur le bouton vert "Use this template" → "Create a new repository"

- Cocher "Include all branches" (pour avoir la branche
solution) - Repository name :
esig-122-demo-films - Visibilité : Public
- Cliquer sur "Create repository"

Étape 2 — Cloner et ouvrir dans WebStorm
- Copier l'URL de votre dépôt :
https://github.com/VOTRE-PSEUDO/esig-122-demo-films.git

- Dans WebStorm : File → New → Project from Version Control...
- Coller l'URL et cliquer sur Clone
- Ouvrir
index.htmldans le navigateur avec Live Edit (icône navigateur en haut à droite)
En classe
Développement live de l'app CinéJS (gestionnaire de films) — phases 1 à 4 (console uniquement) :
- Phase 1 — Données : tableau d'objets
filmsavec 16 films - Phase 2 — Affichage console :
afficherFilmsConsole()avecfor...of,if/else, template literals - Phase 3 — Tri :
trierParNote()avec spread[...]etsort() - Phase 4 — Recherche :
rechercherFilm()avecfilter(),includes(),toLowerCase()
Les phases 5-6 (affichage HTML et contrôles interactifs) seront traitées à la séance 7.
Code de la démo : branche sfa-demo-4.3
Concepts révisés
| Module | Concepts |
|---|---|
| M1 | Variables, const, template literals |
| M2 | Conditions, if/else |
| M3 | Boucles for...of |
| M4 | Fonctions, paramètres, return |
| M5 | filter, sort, spread [...], includes, toLowerCase |
| M6 | Tableau d'objets, accès aux propriétés (notation point) |
Devoirs : Rattraper Nuxy jusqu'au module 6 inclus pour ceux qui sont en retard
Séance 7 - 11 mars 2026 ✓
Thème : CinéJS (suite) + DOM
Exercices Nuxy (~30 min)
Temps en autonomie pour avancer sur les exercices du module 7 (DOM) :
- Exercices 7.1 à 7.7 sur nuxy.ch
CinéJS — Phases 5-6 (~45 min)
Suite de la démo séance 6 : on passe de la console à la page HTML.
- Phase 5 — Affichage HTML :
creerCarteFilm()etafficherFilmsHTML()avecquerySelector,innerHTML,forEach - Phase 6 — Contrôles interactifs :
rafraichir()avecaddEventListener("input", ...), chaînage recherche → tri → affichage
Concepts DOM introduits
| Concept | Description |
|---|---|
querySelector() | Sélectionner un élément par son id ou sélecteur CSS |
innerHTML | Injecter du HTML généré avec des template literals |
addEventListener | Réagir aux actions de l'utilisateur (frappe clavier) |
.value | Lire la valeur d'un champ <input> |
Ressources :
Exercice facultatif : PokéCount
Premier vrai projet dans WebStorm ! Une app de compteur de Pokémon qui met en pratique le DOM dans un projet complet avec HTML, CSS et JavaScript.
- Étapes 1-4 : liaison JS/HTML,
querySelector,textContent, variables, fonctioncapturer() - Énoncé PokéCount
- Démo en ligne
Séance 8 - 25 mars 2026 ✓
Thème : Présentation du projet personnel JavaScript
Contenu (~1h30) :
- Présentation du projet : site web JS natif, affichage dynamique, tri, recherche, ajout, suppression
- Barème : 20 pts projet + 20 pts examen écrit
- 👉 Consignes et barème du projet
- Choix du thème de données (films, recettes, jeux, animaux, etc.)
- Travail autonome : réfléchir à sa ressource, rattrapage Nuxy
Calendrier du projet :
| Date | Séance | Étape projet | Devoirs Nuxy |
|---|---|---|---|
| 25 mars | 8 | Présentation projet | Terminer M7 (DOM) |
| 1er avril | 9 | Copilot + dépôt + données + premier affichage | M8 : 8.1 à 8.4 (événements) |
| 22 avril | 10 | Affichage dynamique (cartes) | M8 : 8.5 à 8.8 (formulaires) |
| 29 avril | 11 | Tri et recherche | Rattrapage si retard |
| 6 mai | 12 | Ajout et suppression (formulaire) | Rattrapage si retard |
| 13 mai | 13 | Finalisation et responsive | Tout terminé |
| 20 mai | 14 | Révisions théoriques | — |
| 27 mai | 15 | Examen blanc | — |
| 7 juin (23h59) | — | Rendu final du projet | — |
| 9 juin | — | Examen de module (30 min) | — |
Devoirs Nuxy obligatoires
Les exercices Nuxy couvrent la théorie nécessaire au projet. Chaque semaine, vous devez terminer le module indiqué avant la séance suivante (~1h de travail à la maison).
Si les exercices ne sont pas faits, vous serez bloqué en classe sur votre projet.
Modules requis pour le projet :
- M7 (DOM) → affichage dynamique
- M8 (événements, formulaires) → tri, recherche, ajout, suppression
Ressources :
Séance 9 - 1er avril 2026 ✓
Thème : Mise en place du projet — Dépôt, Copilot, données et premier affichage
Prérequis Nuxy : M7 (DOM) terminé
Rappel Git (~5 min)
Rappel rapide du workflow Git pour le projet :
- Branches
fix/(corriger un bug) etfeat/(nouvelle fonctionnalité) - Fusionner puis supprimer la branche
- Pour ce projet solo : travailler directement sur
mainest toléré - Toujours faire Commit + Push (= backup sur GitHub)
Étape 1 — Créer le dépôt depuis le template (~5 min)
- Ouvrir le dépôt template : github.com/fallinov/esig-122-projet-template
- Cliquer sur le bouton vert "Use this template" → "Create a new repository"
- Repository name :
122-projet-perso-prenom-nom(ex :122-projet-perso-steve-fallet) - Visibilité : Public (ou privé, au choix)
- Cliquer sur "Create repository"
Étape 2 — Publier sur GitHub Pages (~5 min)
- Sur GitHub → Settings (du dépôt) → Pages (menu gauche)
- Source : Deploy from a branch
- Branch : main / dossier / (root)
- Cliquer Save
- Vérifier dans Actions que le build est terminé (coche verte)
Vérifier la publication
Après chaque git push, GitHub Pages reconstruit automatiquement (~1-2 min). Vérifier dans l'onglet Actions que tout est au vert.
Étape 3 — Cloner dans WebStorm (~5 min)
- Copier l'URL de votre dépôt (pas celle du site GitHub Pages !)
- Dans WebStorm : File → New → Project from Version Control...
- Coller l'URL et cliquer sur Clone
Le template contient la structure exigée par les consignes du projet :
mon-projet/
├── index.html ← Page principale
├── css/
│ └── style.css ← Styles
├── js/
│ └── script.js ← JavaScript
├── img/ ← Images (vide pour l'instant)
├── .jshintrc ← Règles qualité JS
├── .gitignore
└── README.mdÉtape 4 — Envoyer les liens au formateur (~2 min)
Envoyer un message Teams au formateur avec :
- Le lien de votre dépôt GitHub (code source)
- Le lien de votre GitHub Pages (site en ligne)
Étape 5 — Installer GitHub Copilot dans WebStorm (~10 min)
- Settings → Plugins → onglet Marketplace → rechercher "GitHub Copilot" → Install
- Redémarrer WebStorm
- Se connecter à GitHub quand Copilot le demande (icône en bas de l'IDE)
GitHub Copilot gratuit pour les étudiants
Copilot est gratuit avec le GitHub Student Developer Pack. Si vous n'avez pas encore activé votre pack étudiant, faites-le dès que possible.
Modes de Copilot :
| Mode | Usage |
|---|---|
| Ask | Poser une question, obtenir une explication |
| Agent | Lui donner une tâche, il modifie les fichiers |
| Plan | Planifier un développement en plusieurs étapes |
Choisir le bon modèle
- Claude Haiku : tâches simples (génération de données, questions factuelles) — économe en tokens
- Modèles premium (Opus, GPT-4o) : raisonnement complexe — consomme beaucoup plus de tokens
En mode gratuit, vos tokens sont limités. Utilisez Haiku pour les petites tâches !
Étape 6 — Configurer Copilot pour le projet (~5 min)
Créer le fichier .github/copilot-instructions.md à la racine du dépôt :
# Instructions pour GitHub Copilot
## Contexte du Projet
- Projet pédagogique pour apprentis en informatique
- Site web de gestion de collection en JavaScript
- Public cible : étudiants (niveau débutant-intermédiaire)
## Rôle de l'IA
L'IA ne doit **pas** coder à la place de l'apprenti. Son rôle est de :
- **Expliquer** les concepts et la syntaxe
- **Guider** vers la solution (poser des questions)
- **Revoir** le code écrit par l'apprenti
## Langue
- Messages de commit : français
- Code (variables, fonctions) : anglaisCe fichier est lu automatiquement par Copilot à chaque question.
Étape 7 — Générer les données avec Copilot (~15 min)
Dans js/script.js, utilisez GitHub Copilot (mode Agent) pour générer votre tableau de données.
Avant de prompter, vous devez :
- Écrire vous-même un objet exemple avec les propriétés que vous voulez
- Faire valider votre structure par l'enseignant
- Utiliser le prompt ci-dessous dans le chat Copilot (ou une autre IA) en remplaçant les
[...]
Prompt à copier dans Copilot / une IA
Je suis étudiant en informatique et je crée un site web en JavaScript
pour gérer une collection de [TA RESSOURCE, ex: jeux vidéo].
Voici un exemple de ce que je veux obtenir, avec UN objet :
const data = [
{
id: 1,
name: "The Witcher 3",
category: "RPG",
platform: "PC",
rating: 9.5,
year: 2015,
image: "https://placehold.co/400x300/4a90d9/white?text=The+Witcher+3"
}
];
Génère un tableau de 10 objets avec EXACTEMENT les mêmes propriétés
que mon exemple. Les données doivent être réalistes et variées :
- Au moins 3-4 valeurs différentes pour [PROPRIÉTÉ CATÉGORIE, ex: category]
- Des valeurs numériques variées pour [PROPRIÉTÉ TRIABLE, ex: rating]
- Les id de 1 à 10
- Pour chaque image, utilise https://placehold.co/400x300/COULEUR/white?text=NOM
avec une couleur hex différente par catégorie et le nom de l'élément
(espaces remplacés par des +)
Remplace le contenu du tableau data par ces nouvelles données.
Donne-moi UNIQUEMENT le code JavaScript, rien d'autre.Exemple de résultat attendu
const data = [
{
id: 1,
name: "The Witcher 3",
category: "RPG",
platform: "PC",
rating: 9.5,
year: 2015,
image: "https://placehold.co/400x300/4a90d9/white?text=The+Witcher+3"
},
{
id: 2,
name: "FIFA 25",
category: "Sport",
platform: "PS5",
rating: 7.2,
year: 2024,
image: "https://placehold.co/400x300/2ecc71/white?text=FIFA+25"
},
// ... 8 autres objets
];Les images placeholder affichent le nom sur un fond coloré par catégorie. Tu les remplaceras plus tard par de vraies images dans un dossier img/.
Étape 8 — Afficher les données dans la page (~15 min)
Afficher les données sous forme de liste <ul> simple dans la page.
Objectif : pour chaque élément du tableau, créer un <li> avec le nom et l'image.
Indice — avec forEach
// Récupère la liste
const ulList = document.getElementById("list");
// Parcours le tableau et crée un <li> par élément
data.forEach(item => {
ulList.innerHTML += `
<li>
<div>${item.name}</div>
<div><img src="${item.image}" alt="${item.name}"></div>
</li>`;
});Une fois l'affichage fonctionnel :
- Vérifier que la page fonctionne en local (ouvrir
index.htmldans le navigateur) - Commit + Push → vérifier sur GitHub Pages que le site est à jour
- Vérifier qu'il n'y a aucune erreur dans la console du navigateur (F12)
Code de la démo : fallinov/122-projet-perso-steve-fallet
Devoirs pour la séance 10
Nuxy : Exercices 8.1 à 8.4 (événements)
Projet : Avoir la structure HTML/CSS de base + le tableau d'objets dans js/script.js + affichage <ul> fonctionnel sur GitHub Pages. Commencer à styliser l'affichage (CSS, cartes, tableau...).
Ressources :
Séance 10 - 22 avril 2026
Thème : Projet — Affichage dynamique avec fonction et cartes CSS
Prérequis Nuxy : M8 exercices 8.1 à 8.4 (événements)
Prérequis projet : Tableau de données + affichage basique fonctionnel (séance 9)
Objectifs
- Encapsuler l'affichage dans une fonction réutilisable
- Remplacer la liste basique par des cartes HTML/CSS
- Comprendre pourquoi une fonction d'affichage est nécessaire (tri, recherche, ajout necessitent de rafraîchir)
Étape 1 — Créer la fonction displayItems() (~20 min)
Transformer le code de la séance 9 en une fonction réutilisable :
/**
* Affiche les éléments dans la page
* @param {Array} items - Tableau d'objets à afficher
*/
function displayItems(items) {
const container = document.getElementById("list");
let html = "";
items.forEach(item => {
html += `<article class="card">...</article>`;
});
container.innerHTML = html;
}
// Appel au chargement de la page
displayItems(data);Pourquoi une fonction ?
Plus tard, vous aurez besoin de rafraîchir l'affichage après un tri, une recherche ou un ajout. Avoir une fonction permet de la rappeler à chaque modification :
// Après un tri
const sorted = [...data].sort((a, b) => b.rating - a.rating);
displayItems(sorted);Étape 2 — Créer le HTML d'une carte (~20 min)
Remplacer le simple <li> par une carte plus riche avec image, titre et infos :
Exemple de structure HTML pour une carte
<article class="card">
<img src="..." alt="...">
<div class="card-body">
<h2>Nom de l'élément</h2>
<p>Catégorie — Année</p>
<span class="rating">9.5</span>
</div>
</article>Adapter la structure à votre thème (films, recettes, animaux...).
Étape 3 — Styliser les cartes en CSS (~30 min)
Mettre en forme les cartes avec CSS :
- Grille responsive (
display: gridouflexboxavecflex-wrap) - Carte avec ombre, bordure arrondie, hover
- Image en haut, contenu en bas
- Responsive : 1 colonne mobile, 2-3 colonnes desktop
Exemple CSS minimal
#list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
list-style: none;
padding: 0;
}
.card {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
transition: transform 0.2s;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.card img {
width: 100%;
height: 200px;
object-fit: cover;
}
.card-body {
padding: 1rem;
}Étape 4 — Commit + Push + Vérifier (~5 min)
- Vérifier le rendu en local et sur mobile (DevTools → responsive)
- Console propre (F12, pas d'erreurs)
- Commit + Push avec un message clair (ex :
feat: affichage en cartes avec CSS) - Vérifier sur GitHub Pages
Devoirs pour la séance 11
Nuxy : Exercices 8.5 à 8.8 (formulaires)
Projet : L'affichage dynamique avec cartes doit être fonctionnel et déployé sur GitHub Pages
Ressources :
Séance 11 - 29 avril 2026
Thème : Projet — Tri, recherche et bonnes pratiques d'affichage
Prérequis Nuxy : M8 terminé (événements + formulaires)
Prérequis projet : Affichage en cartes fonctionnel (séance 10)
Objectifs
- Comprendre pourquoi
innerHTML +=dans une boucle est une mauvaise pratique - Refactoriser la fonction d'affichage pour qu'elle soit performante
- Ajouter un bouton de tri sur la collection
- Ajouter un champ de recherche
- Chaîner recherche + tri pour afficher le résultat correct
Étape 1 — Corriger la fonction d'affichage (~15 min)
À la séance 10, vous avez probablement écrit votre fonction d'affichage comme ceci :
// ❌ Pattern à éviter
function displayItems(items) {
const container = document.getElementById("list");
container.innerHTML = "";
items.forEach(item => {
container.innerHTML += `<article class="card">...</article>`;
});
}Pourquoi c'est un problème ?
Chaque fois que vous écrivez dans innerHTML, le navigateur :
- Lit tout le HTML existant dans le conteneur
- Le concatène avec votre nouveau morceau
- Reconstruit entièrement le DOM du conteneur
Avec 10 cartes, le navigateur reconstruit le DOM 10 fois de suite. Pour 1000 cartes, ce serait dramatique. C'est ce qu'on appelle un anti-pattern : ça marche, mais c'est mauvais.
La correction : accumuler puis écrire une seule fois
// ✅ Pattern recommandé
function displayItems(items) {
const container = document.getElementById("list");
let html = "";
items.forEach(item => {
html += `
<article class="card" data-id="${item.id}">
<img src="${item.image}" alt="${item.name}">
<div class="card-body">
<h2>${item.name}</h2>
<p>${item.category} — ${item.year}</p>
<span class="rating">${item.rating}</span>
</div>
</article>
`;
});
container.innerHTML = html; // Une seule écriture DOM !
}Deux changements clés :
- La variable
htmlaccumule le texte, on écrit dans le DOM une seule fois à la fin. - L'attribut
data-id="${item.id}"permet d'identifier chaque carte (utile en séance 12 pour la suppression).
Étape 2 — Bouton de tri qui inverse l'ordre (~25 min)
Ajouter un bouton qui trie par note. À chaque clic, l'ordre s'inverse (croissant ↔ décroissant) et le texte du bouton est mis à jour.
HTML (au-dessus de la liste) :
<button id="btn-sort">Trier par note ↓</button>JavaScript :
const btnSort = document.getElementById("btn-sort");
// État du tri : true = croissant, false = décroissant
let sortAsc = false;
btnSort.addEventListener("click", () => {
sortAsc = !sortAsc; // inverser l'état à chaque clic
const sorted = [...data].sort((a, b) =>
sortAsc ? a.rating - b.rating : b.rating - a.rating
);
// Mettre à jour le texte du bouton selon le sens du tri
btnSort.textContent = sortAsc ? "Trier par note ↑" : "Trier par note ↓";
displayItems(sorted);
});Concepts introduits :
addEventListener("click", ...): réagir à un clic- État : une variable (
sortAsc) mémorise la situation actuelle entre deux clics !sortAsc: opérateur NON logique pour inverser un booléen[...data]: copier le tableau pour ne pas modifier l'originalArray.sort((a, b) => ...)avec ternaire : choisir le sens du tri à la volée.textContent: modifier le texte affiché du bouton
Pourquoi copier le tableau avec [...data] ?
sort() modifie le tableau d'origine. Sans la copie, vous perdriez l'ordre initial après le premier clic. Avec [...data], le tableau data reste intact, et chaque clic retrie depuis l'ordre de départ.
Comprendre a.rating - b.rating vs b.rating - a.rating
- Si la soustraction est positive,
sort()placeaaprèsb. - Si elle est négative,
aest placé avantb.
Donc a.rating - b.rating trie du plus petit au plus grand (croissant), et b.rating - a.rating du plus grand au plus petit (décroissant). C'est pour ça qu'inverser les variables suffit à inverser l'ordre.
Étape 3 — Champ de recherche (~25 min)
Ajouter un champ qui filtre les jeux selon le nom saisi.
HTML :
<input type="text" id="search" placeholder="Rechercher un jeu...">JavaScript :
const searchInput = document.getElementById("search");
searchInput.addEventListener("input", () => {
const query = searchInput.value.toLowerCase();
const filtered = data.filter(item =>
item.name.toLowerCase().includes(query)
);
displayItems(filtered);
});Concepts introduits :
addEventListener("input", ...): réagir à chaque frappe au clavier.value: lire le contenu actuel du champArray.filter(): garder seulement les éléments qui correspondentString.includes()+toLowerCase(): recherche insensible à la casse
Étape 4 — Chaîner tri + recherche (~10 min)
Si on déclenche tri puis recherche, le second appel écrase le premier. Pour combiner, on regroupe la logique dans une seule fonction refresh() appelée à chaque interaction. Elle filtre d'abord, puis trie selon l'état sortAsc.
function refresh() {
const query = searchInput.value.toLowerCase();
// 1. Filtrer selon le champ de recherche
let result = data.filter(item =>
item.name.toLowerCase().includes(query)
);
// 2. Trier selon l'état du bouton
result = [...result].sort((a, b) =>
sortAsc ? a.rating - b.rating : b.rating - a.rating
);
// 3. Afficher
displayItems(result);
}
// Recherche : à chaque frappe, on rafraîchit
searchInput.addEventListener("input", refresh);
// Tri : on inverse l'état, on met à jour le bouton, puis on rafraîchit
btnSort.addEventListener("click", () => {
sortAsc = !sortAsc;
btnSort.textContent = sortAsc ? "Trier par note ↑" : "Trier par note ↓";
refresh();
});Pourquoi refresh() plutôt que deux fonctions séparées ?
Si la recherche faisait son propre affichage de son côté et le tri aussi, ils s'écraseraient mutuellement (taper dans la recherche annulerait le tri en cours). En centralisant dans refresh(), on combine systématiquement filtre + tri avant chaque affichage.
Étape 5 — Commit + Push + Vérifier (~5 min)
- Tester le tri et la recherche dans le navigateur
- Vérifier la console (F12) : aucune erreur
- Commit + Push avec un message clair (ex :
feat: tri et recherche) - Vérifier sur GitHub Pages que tout fonctionne en ligne
⚠️ À retenir pour la séance 12 — la délégation d'événements
Aujourd'hui, vos écouteurs sont sur <input> et <button>, qui restent dans la page : pas de souci. Mais en séance 12, vous mettrez un bouton Supprimer sur chaque carte.
Problème : à chaque appel de displayItems(), le navigateur reconstruit toutes les cartes. Les listeners attachés directement aux cartes disparaissent :
// ❌ Ne fonctionnera plus après un tri ou une recherche
document.querySelectorAll(".card").forEach(card => {
card.addEventListener("click", () => alert("clic !"));
});Solution : la délégation d'événements. Un seul listener sur le parent stable (#list), qui détecte sur quelle carte on a cliqué grâce à event.target.closest(".card") :
// ✅ Un listener pour toutes les cartes, présentes ET futures
document.getElementById("list").addEventListener("click", (event) => {
const card = event.target.closest(".card");
if (!card) return;
console.log("Carte cliquée, id :", card.dataset.id);
});C'est pour ça qu'on a ajouté data-id à chaque carte en étape 1. On l'utilisera dès la semaine prochaine.
Devoirs pour la séance 12
Projet : Le tri et la recherche doivent être fonctionnels et déployés sur GitHub Pages.
Ressources :
Séance 12 - 6 mai 2026
Thème : Projet — Ajout et suppression
Objectifs
- Comprendre la structure d'un formulaire HTML et intercepter sa soumission
- Ajouter une ressource au tableau avec
push()et rafraîchir l'affichage - Utiliser la délégation d'événements (préparée séance 11) pour les boutons Supprimer
- Supprimer un élément avec
filter()sans muter le tableau d'origine
Étape 1 — Créer le formulaire HTML (~20 min)
Ajouter le formulaire dans index.html, au-dessus ou à côté de la liste :
<form id="form-add">
<h2>Ajouter</h2>
<div class="form-group">
<label for="input-name">Nom</label>
<input type="text" id="input-name" placeholder="Ex : The Witcher 3" required>
</div>
<div class="form-group">
<label for="input-category">Catégorie</label>
<select id="input-category">
<option value="RPG">RPG</option>
<option value="Action">Action</option>
<option value="Stratégie">Stratégie</option>
</select>
</div>
<div class="form-group">
<label for="input-rating">Note (1–10)</label>
<input type="number" id="input-rating" min="1" max="10" placeholder="8">
</div>
<button type="submit">Ajouter</button>
</form>CSS pour le formulaire :
.form-group {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 12px;
}
/* Cibler uniquement les champs du formulaire, pas tous les inputs de la page */
.form-group input,
.form-group select {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: #0078d4;
}
form button[type="submit"] {
padding: 10px 20px;
background-color: #0078d4;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
form button[type="submit"]:hover {
background-color: #005fa3;
}Points clés :
<label for="...">+id="..."sur l'input : cliquer le label met le focus sur le champtype="number"+min/max: validation native du navigateurrequired: le navigateur refuse la soumission si le champ est videtype="submit"déclenche l'événementsubmitsur le<form>parent
Étape 2 — Intercepter la soumission et ajouter au tableau (~25 min)
const form = document.getElementById("form-add");
const inputName = document.getElementById("input-name");
const inputCategory = document.getElementById("input-category");
const inputRating = document.getElementById("input-rating");
form.addEventListener("submit", (event) => {
event.preventDefault(); // Empêcher le rechargement de la page
const newItem = {
id: Date.now(), // ID unique basé sur l'horodatage
name: inputName.value.trim(), // trim() supprime les espaces en début/fin
category: inputCategory.value,
rating: Number(inputRating.value), // .value est toujours une string → convertir
image: "img/default.jpg"
};
data.push(newItem); // Ajouter au tableau
refresh(); // Rafraîchir l'affichage
form.reset(); // Vider tous les champs en une ligne
});Concepts introduits :
event.preventDefault(): empêcher le comportement par défaut du<form>(rechargement ou envoi vers un serveur).value.trim(): lire la valeur et supprimer les espaces superflusNumber(): convertir la chaîne en nombre ("8"→8) — les.valuesont toujours des stringsDate.now(): horodatage en millisecondes, unique à chaque soumission → bon ID temporaireform.reset(): réinitialiser tous les champs du formulaire en une seule instruction
Pourquoi Date.now() comme ID ?
En production, les IDs viennent d'une base de données (1, 2, 3…). En JS pur, sans serveur, Date.now() donne un entier unique à chaque milliseconde — suffisant pour un projet personnel où on n'ajoute jamais deux éléments en même temps.
Étape 3 — Ajouter le bouton Supprimer sur chaque carte (~15 min)
Depuis la séance 11, displayItems() génère data-id="${item.id}" sur chaque carte. On y ajoute maintenant le bouton :
function displayItems(items) {
const container = document.getElementById("list");
let html = "";
items.forEach(item => {
html += `
<article class="card" data-id="${item.id}">
<img src="${item.image}" alt="${item.name}">
<div class="card-body">
<h2>${item.name}</h2>
<p>${item.category} — ${item.year}</p>
<span class="rating">${item.rating} ⭐</span>
<button class="btn-delete">Supprimer</button>
</div>
</article>
`;
});
container.innerHTML = html;
}Ajouter dans style.css le style du bouton :
.btn-delete {
margin-top: 8px;
padding: 6px 12px;
background-color: #e74c3c;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
}
.btn-delete:hover {
background-color: #c0392b;
}Étape 4 — Supprimer avec la délégation d'événements (~20 min)
Rappel de la séance 11 : les boutons sont recréés à chaque displayItems(), donc un listener direct dessus disparaîtrait. On délègue au conteneur parent stable (#list) :
document.getElementById("list").addEventListener("click", (event) => {
// Vérifier si le clic vient d'un bouton Supprimer
const btn = event.target.closest(".btn-delete");
if (!btn) return; // Clic ailleurs sur la carte → ignorer
// Remonter à la carte pour récupérer l'id
const card = btn.closest(".card");
const id = Number(card.dataset.id); // dataset.id est une string → convertir
// Confirmation avant suppression
if (!confirm("Supprimer cet élément ?")) return;
// Recréer le tableau sans l'élément supprimé
data = data.filter(item => item.id !== id);
refresh();
});Concepts introduits :
event.target.closest(".btn-delete"): remonter dans le DOM jusqu'à trouver l'ancêtre correspondant (ounull)card.dataset.id: lire l'attributdata-idde la carteNumber(...):dataset.idest une string, il faut la convertir pour comparer avec===confirm(): boîte de dialogue native (retournetrueoufalse)data = data.filter(...): remplacer le tableau par une version sans l'élément supprimé
closest() vs event.target
event.target est l'élément exactement cliqué — peut être le texte à l'intérieur du bouton, pas le bouton lui-même. closest(".btn-delete") remonte dans les parents jusqu'à trouver un élément qui correspond au sélecteur. C'est la bonne façon de faire de la délégation.
data = data.filter(...) exige let
Si data est déclaré avec const, la réassignation lève une erreur Assignment to constant variable. Vérifiez que votre tableau est bien let data = [...] en haut du fichier.
Étape 5 — Commit + Push + Vérifier (~10 min)
- Tester l'ajout : remplir → soumettre → carte apparaît → formulaire vidé
- Tester la suppression : clic Supprimer → confirmation → carte disparaît
- Tester la combinaison : ajouter, trier, rechercher, puis supprimer → tout reste cohérent
- Console (F12) : zéro erreur
- Commit + Push (ex :
feat: ajout et suppression) - Vérifier sur GitHub Pages que tout fonctionne en ligne
Devoirs pour la séance 13
Projet : L'ajout et la suppression doivent être fonctionnels et déployés sur GitHub Pages.
Ressources :
- Créer des formulaires
- Récupérer les valeurs des champs
- Valider les saisies
- Envoyer un formulaire
- Événements DOM
Séance 13 - 13 mai 2026
Thème : Projet — Finalisation et responsive design
Contenu (~1h30) :
- Responsive : media queries CSS ou grille flexible (grid/flexbox)
- Tester sur mobile (DevTools → mode responsive)
- Cas limites : message « Aucun résultat », validation formulaire
- Compteur d'éléments
- README.md du projet
- 0 erreurs console
- Commit + push
Rendu final
Le projet doit être rendu le 7 juin 2026 à 23h59 sur GitHub. Il reste 3 semaines après cette séance pour peaufiner à la maison.
Nuxy
Tous les modules doivent être terminés pour l'examen. S'il vous reste des exercices en retard, c'est le moment de rattraper.
Séance 14 - 20 mai 2026
Thème : Révisions théoriques
Contenu (~1h30) :
- Révision des concepts clés (M1-M8)
- Exercices de synthèse type examen
- Questions/réponses sur les points difficiles
Concepts à réviser :
| Module | Concepts clés |
|---|---|
| M1 | Variables (let, const), types, template literals |
| M2 | Conditions (if/else, switch, ternaire) |
| M3 | Boucles (for, for...of, while) |
| M4 | Fonctions, paramètres, return, arrow functions |
| M5-M6 | Tableaux, objets, filter, sort, map |
| M7 | DOM (querySelector, innerHTML, createElement) |
| M8 | Événements (addEventListener), formulaires |
Séance 15 - 27 mai 2026
EXAMEN BLANC
Format (~1h30) :
- Questions théoriques (QCM, vrai/faux)
- Lecture et analyse de code
- Écriture de code (exercices pratiques)
- Couvre tous les modules 1-8
Dates importantes
- 7 juin 2026 (23h59) : rendu final du projet sur GitHub
- 9 juin 2026 : examen de module (30 min)
Récapitulatif des objectifs
| Objectif officiel | Module(s) | Couvert en C122 ? |
|---|---|---|
| Enjeux de la programmation navigateur | M1, M7 | ✅ |
| Syntaxe de base du langage | M1-M4 | ✅ |
| Gérer des listes et structures de données | M5-M6 | ✅ |
| Manipuler dynamiquement les éléments (DOM) | M7 | ✅ |
| Créer et manipuler les formulaires | M8 | ✅ |
| Gérer les interactions utilisateur | M8 | ✅ |
| Gérer les erreurs | M9 | ⏭ Reporté en C141 |
| Consommer une API (CRUD) | M9-M10 | ⏭ Reporté en C141 |
Pour aller plus loin (optionnel)
Nuxy contient deux modules au-delà du programme C122 :
Module 9 — Promesses & API
- Comprendre les
Promiseetasync/await - Récupérer des données avec
fetch()(GET) - Gérer les erreurs API
- Envoyer/modifier/supprimer des données (POST, PUT, DELETE)
Module 10 — Mini-projet guidé
- Construire une mini-app produits avec API CRUD complète
- Recherche, tri, filtre par catégorie
- Ajout/modification/suppression depuis un formulaire
Pour les élèves qui continuent en ESIG2
Les modules 9 et 10 anticipent ce que vous ferez en C141 (Vue.js) : appels API, gestion d'erreurs, formulaires CRUD. Si vous avez fini votre projet C122 en avance, faire ces deux modules vous donnera une longueur d'avance pour le C141.
Hors-scope examen C122
Ces modules ne seront pas évalués à l'examen de module C122 (9 juin 2026, 30 min) — l'examen porte uniquement sur M1-M8.