Skip to content

Plan d'enseignement - Cours 122

Vue d'ensemble des 15 séances

SéanceDateModuleContenuExercices Nuxy
121.01M1Bases JavaScript1.1 - 1.9
228.01M2Conditions2.1 - 2.6
304.02M3Boucles3.1 - 3.4
411.02M4Fonctions4.1 - 4.4
525.02M5Tableaux (bases)5.1 - 6.10
604.03M1-M7Démo CinéJS + Intro DOM7.1 - 7.7
711.03M7DOMTerminer M7
825.03ProjetPrésentation projet + validation ressource8.1 - 8.4
901.04ProjetCopilot + dépôt + données + premier affichage8.5 - 8.8
1022.04ProjetAffichage dynamique (cartes) + CSSRattrapage
1129.04ProjetTri et rechercheRattrapage
1206.05ProjetAjout et suppressionTout terminé
1313.05ProjetFinalisation et responsive design-
1420.05-Révisions théoriques-
1527.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 let et const
  • 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 for et for...of
  • Comprendre do...while et break

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 avec filter()

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

  1. Ouvrir le dépôt template : github.com/fallinov/esig-122-demo-films
  2. Cliquer sur le bouton vert "Use this template""Create a new repository"

Bouton "Use this template" sur GitHub

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

Formulaire de création avec "Include all branches" coché

Étape 2 — Cloner et ouvrir dans WebStorm

  1. Copier l'URL de votre dépôt : https://github.com/VOTRE-PSEUDO/esig-122-demo-films.git

Bouton "Code" pour copier l'URL de clonage

  1. Dans WebStorm : FileNewProject from Version Control...
  2. Coller l'URL et cliquer sur Clone
  3. Ouvrir index.html dans 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 films avec 16 films
  • Phase 2 — Affichage console : afficherFilmsConsole() avec for...of, if/else, template literals
  • Phase 3 — Tri : trierParNote() avec spread [...] et sort()
  • Phase 4 — Recherche : rechercherFilm() avec filter(), 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

ModuleConcepts
M1Variables, const, template literals
M2Conditions, if/else
M3Boucles for...of
M4Fonctions, paramètres, return
M5filter, sort, spread [...], includes, toLowerCase
M6Tableau 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) :

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() et afficherFilmsHTML() avec querySelector, innerHTML, forEach
  • Phase 6 — Contrôles interactifs : rafraichir() avec addEventListener("input", ...), chaînage recherche → tri → affichage

Concepts DOM introduits

ConceptDescription
querySelector()Sélectionner un élément par son id ou sélecteur CSS
innerHTMLInjecter du HTML généré avec des template literals
addEventListenerRéagir aux actions de l'utilisateur (frappe clavier)
.valueLire 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.

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 :

DateSéanceÉtape projetDevoirs Nuxy
25 mars8Présentation projetTerminer M7 (DOM)
1er avril9Copilot + dépôt + données + premier affichageM8 : 8.1 à 8.4 (événements)
22 avril10Affichage dynamique (cartes)M8 : 8.5 à 8.8 (formulaires)
29 avril11Tri et rechercheRattrapage si retard
6 mai12Ajout et suppression (formulaire)Rattrapage si retard
13 mai13Finalisation et responsiveTout terminé
20 mai14Révisions théoriques
27 mai15Examen blanc
7 juin (23h59)Rendu final du projet
9 juinExamen 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) et feat/ (nouvelle fonctionnalité)
  • Fusionner puis supprimer la branche
  • Pour ce projet solo : travailler directement sur main est toléré
  • Toujours faire Commit + Push (= backup sur GitHub)

Étape 1 — Créer le dépôt depuis le template (~5 min)

  1. Ouvrir le dépôt template : github.com/fallinov/esig-122-projet-template
  2. Cliquer sur le bouton vert "Use this template""Create a new repository"
  3. Repository name : 122-projet-perso-prenom-nom (ex : 122-projet-perso-steve-fallet)
  4. Visibilité : Public (ou privé, au choix)
  5. Cliquer sur "Create repository"

Étape 2 — Publier sur GitHub Pages (~5 min)

  1. Sur GitHub → Settings (du dépôt) → Pages (menu gauche)
  2. Source : Deploy from a branch
  3. Branch : main / dossier / (root)
  4. Cliquer Save
  5. 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)

  1. Copier l'URL de votre dépôt (pas celle du site GitHub Pages !)
  2. Dans WebStorm : FileNewProject from Version Control...
  3. 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)

  1. SettingsPlugins → onglet Marketplace → rechercher "GitHub Copilot" → Install
  2. Redémarrer WebStorm
  3. 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 :

ModeUsage
AskPoser une question, obtenir une explication
AgentLui donner une tâche, il modifie les fichiers
PlanPlanifier 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 :

md
# 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) : anglais

Ce 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 :

  1. Écrire vous-même un objet exemple avec les propriétés que vous voulez
  2. Faire valider votre structure par l'enseignant
  3. Utiliser le prompt ci-dessous dans le chat Copilot (ou une autre IA) en remplaçant les [...]

Prompt à copier dans Copilot / une IA

text
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
js
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
js
// 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 :

  1. Vérifier que la page fonctionne en local (ouvrir index.html dans le navigateur)
  2. Commit + Push → vérifier sur GitHub Pages que le site est à jour
  3. 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 :

js
/**
 * 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 :

js
// 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
html
<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: grid ou flexbox avec flex-wrap)
  • Carte avec ombre, bordure arrondie, hover
  • Image en haut, contenu en bas
  • Responsive : 1 colonne mobile, 2-3 colonnes desktop
Exemple CSS minimal
css
#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)

  1. Vérifier le rendu en local et sur mobile (DevTools → responsive)
  2. Console propre (F12, pas d'erreurs)
  3. Commit + Push avec un message clair (ex : feat: affichage en cartes avec CSS)
  4. 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 :

js
// ❌ 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 :

  1. Lit tout le HTML existant dans le conteneur
  2. Le concatène avec votre nouveau morceau
  3. 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

js
// ✅ 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 :

  1. La variable html accumule le texte, on écrit dans le DOM une seule fois à la fin.
  2. 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) :

html
<button id="btn-sort">Trier par note ↓</button>

JavaScript :

js
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'original
  • Array.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() place a après b.
  • Si elle est négative, a est placé avant b.

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 :

html
<input type="text" id="search" placeholder="Rechercher un jeu...">

JavaScript :

js
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 champ
  • Array.filter() : garder seulement les éléments qui correspondent
  • String.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.

js
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)

  1. Tester le tri et la recherche dans le navigateur
  2. Vérifier la console (F12) : aucune erreur
  3. Commit + Push avec un message clair (ex : feat: tri et recherche)
  4. 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 :

js
// ❌ 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") :

js
// ✅ 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 :

html
<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 :

css
.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 champ
  • type="number" + min/max : validation native du navigateur
  • required : le navigateur refuse la soumission si le champ est vide
  • type="submit" déclenche l'événement submit sur le <form> parent

Étape 2 — Intercepter la soumission et ajouter au tableau (~25 min)

js
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 superflus
  • Number() : convertir la chaîne en nombre ("8"8) — les .value sont toujours des strings
  • Date.now() : horodatage en millisecondes, unique à chaque soumission → bon ID temporaire
  • form.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 :

js
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 :

css
.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) :

js
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 (ou null)
  • card.dataset.id : lire l'attribut data-id de la carte
  • Number(...) : dataset.id est une string, il faut la convertir pour comparer avec ===
  • confirm() : boîte de dialogue native (retourne true ou false)
  • 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)

  1. Tester l'ajout : remplir → soumettre → carte apparaît → formulaire vidé
  2. Tester la suppression : clic Supprimer → confirmation → carte disparaît
  3. Tester la combinaison : ajouter, trier, rechercher, puis supprimer → tout reste cohérent
  4. Console (F12) : zéro erreur
  5. Commit + Push (ex : feat: ajout et suppression)
  6. 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 :

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 :

ModuleConcepts clés
M1Variables (let, const), types, template literals
M2Conditions (if/else, switch, ternaire)
M3Boucles (for, for...of, while)
M4Fonctions, paramètres, return, arrow functions
M5-M6Tableaux, objets, filter, sort, map
M7DOM (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 officielModule(s)Couvert en C122 ?
Enjeux de la programmation navigateurM1, M7
Syntaxe de base du langageM1-M4
Gérer des listes et structures de donnéesM5-M6
Manipuler dynamiquement les éléments (DOM)M7
Créer et manipuler les formulairesM8
Gérer les interactions utilisateurM8
Gérer les erreursM9⏭ 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 Promise et async/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.

Documentation pour les cours de développement web