Skip to content

Module 11 : JavaScript – Création et manipulation avancée du DOM, validation et objets

Introduction

Ce module approfondit la manipulation du DOM en JavaScript, en se concentrant sur la création dynamique d’éléments, la gestion des classes CSS, la validation avancée avec les expressions régulières, et l’utilisation de tableaux et objets pour générer du contenu HTML.

Objectifs du cours

  • Comprendre comment créer et insérer dynamiquement des éléments dans le DOM avec JavaScript
  • Maîtriser l’utilisation de classList pour manipuler les classes CSS
  • Valider des champs de formulaire à l’aide d’expressions régulières
  • Utiliser des tableaux et objets pour générer et mettre à jour dynamiquement le contenu HTML

Théorie

1 : Manipulation des classes CSS avec classList

Définition

La propriété classList permet d’ajouter, de retirer, de basculer ou de vérifier la présence de classes CSS sur un élément HTML.

Contexte d’utilisation

classList est très utile pour gérer dynamiquement l’apparence des éléments (ex : afficher/masquer, indiquer une erreur, changer de thème, etc.).

Exemples pratiques

javascript
// Ajouter une classe
element.classList.add('active');

// Retirer une classe
element.classList.remove('error');

// Basculer une classe
element.classList.toggle('visible');

// Vérifier la présence
if (element.classList.contains('selected')) {
    // faire quelque chose
}
html
<label id="lblNom" for="nom">Nom :</label>
<input type="text" id="nom">
css
.erreur {
    color: red;
}
javascript
/**
 * Valide le champ de nom et ajoute une classe d'erreur si le champ est vide. Utilise `input` pour une validation en temps réel et `classList` pour gérer les classes CSS de manière efficace.
 */
function validationNom() {
  const labelNom = document.getElementById('lblNom');
  const inputNom = document.getElementById('nom');

  // Trim permet de supprimer les espaces avant et après la valeur
  if (inputNom.value.trim() === '') 
  {
      // Si le champ est vide, ajouter la classe d'erreur
      labelNom.classList.add('erreur');
  } 
  else 
  {
      // Sinon, on doit penser à retirer la classe d'erreur
      labelNom.classList.remove('erreur');
  }
}

function initialisation() {
  const inputNom = document.getElementById('nom');

  // On utilise 'input' pour valider en temps réel à chaque modification du champ. On aurait aussi pu utiliser 'blur' pour valider uniquement lorsque l'utilisateur quitte le champ.
  inputNom.addEventListener('input', validationNom);
}
addEventListener('load', initialisation);

Note : input vérifie à chaque modification du champ, tandis que blur vérifie uniquement lorsque l'utilisateur quitte le champ. Choisissez en fonction de l'expérience utilisateur souhaitée.

Avantages de classList

Plus simple et plus lisible que manipuler directement l’attribut class et permet d'ajouter/retirer plusieurs classes facilement au lieu de "tout remplacer" l'attribut class.

Avantage de toggle

toggle est particulièrement utile pour appliquer une classe, si elle n’est pas présente, ou la retirer si elle est déjà appliquée, ce qui est idéal pour les fonctionnalités d’affichage/masquage.

css
.hidden {
    display: none;
}
html
<button id="toggleImage">Afficher/Masquer l'image</button>
<img id="image" src="image.jpg" alt="Image à afficher/masquer">
javascript
// Afficher/masquer une image au clic d'un bouton
let bouton = document.getElementById('toggleImage');
let image = document.getElementById('image');

function gererClick() {
    // Si la classe 'hidden' est présente dans la liste de classes de l'image : elle sera retirée
    // Si la classe 'hidden' n'est pas présente dans la liste de classes de l'image : elle sera ajoutée
    image.classList.toggle('hidden');
}

bouton.addEventListener('click', gererClick);

2 : Création et ajout d’éléments dans le DOM

Définition

Créer et ajouter dynamiquement des éléments HTML dans le DOM permet de modifier la structure d’une page web en réponse à des actions utilisateur ou à des besoins applicatifs, sans recharger la page.

Contexte d’utilisation

On utilise ces méthodes pour générer dynamiquement du contenu (ex : ajouter des messages, des cartes, des listes, etc.) ou pour construire des interfaces interactives. Lorsqu'on veut alors ajouter une ou des balises HTML dans une page web, on va prévilégier cette façon de faire plutôt que d'utiliser innerHTML qui est plus rapide à écrire mais moins performante et plus risquée (risque de faille XSS).

createElement()

La méthode createElement() permet de créer un nouvel élément HTML à partir de son nom de balise. Par exemple, document.createElement('div') crée une nouvelle balise <div> qui n'est pas encore ajoutée à la page web (DOM). createElement('a') crée une balise <a>, createElement('p') crée une balise <p>, etc.

appendChild()

La méthode appendChild() permet d'ajouter un élément en tant que dernier enfant d'un élément parent dans le DOM. Par exemple, parent.appendChild(child) ajoute l'élément child à la fin de la liste des enfants de parent. Si child est déjà présent ailleurs dans le DOM, il sera déplacé à sa nouvelle position.

Départ

html
<div id="parent">
    <p>Premier enfant</p>
    <p>Deuxième enfant</p>
    <!-- NOUVEL ENFANT SERA AJOUTÉ ICI -->
</div>

Modification avec appendChild()

javascript
let parent = document.getElementById('parent');
let newChild = document.createElement('p');
newChild.textContent = "Nouvel enfant ajouté avec appendChild";
parent.appendChild(newChild);

Résultat

html
<div id="parent">
    <p>Premier enfant</p>
    <p>Deuxième enfant</p>
    <p>Nouvel enfant ajouté avec appendChild</p> 
</div>

insertBefore()

La méthode insertBefore() permet d'insérer un élément avant un élément de référence dans le DOM. Par exemple, parent.insertBefore(child, reference) ajoute l'élément child avant l'élément reference dans la liste des enfants de parent.

Départ

html
<div id="parent">
    <p>Premier enfant</p>
     <!-- NOUVEL ENFANT SERA AJOUTÉ ICI, JUSTE AVANT CE PARAGRAPHE -->
    <p id="reference">Deuxième enfant (référence)</p>
</div>
javascript
let parent = document.getElementById('parent');
let newChild = document.createElement('p');
newChild.textContent = "Nouvel enfant ajouté avec insertBefore";
let reference = document.getElementById('reference');
parent.insertBefore(newChild, reference);

Résultat

html
<div id="parent">
    <p>Premier enfant</p>
    <p>Nouvel enfant ajouté avec insertBefore</p> 
    <p id="reference">Deuxième enfant (référence)</p>
</div>

remove()

La méthode remove() permet de supprimer un élément du DOM. Par exemple, element.remove() supprime l'élément ciblé de la page web.

html
<div id="parent">
    <p>Premier enfant</p>
    <p id="toRemove">Deuxième enfant à supprimer</p>
    <p>Troisième enfant</p>
</div>
javascript
let elementToRemove = document.getElementById('toRemove');
elementToRemove.remove();

Résultat

html
<div id="parent">
    <p>Premier enfant</p>
    <!-- <p id="toRemove">Deuxième enfant à supprimer</p> -->
    <p>Troisième enfant</p>
</div>

Exemple 1 : ajouter à la fin de <body>

Créer un élément HTML, lui associer des attributs, et l'ajouter à la page web (DOM).

javascript
// Créer un nouvel élément <div>
let newDiv = document.createElement("div");

// Si c'est une balise de contenu ou, y ajouter du texte
newDiv.textContent = "Ceci est une nouvelle div créée dynamiquement !";

// Ajouter sa ou ses classes, son id, ses attributs, etc.
newDiv.classList.add("my-class");
newDiv.setAttribute("id", "div1");

// Ajouter la balise créee à la page web (DOM), à l'endroit désiré.
// Dans ce cas-ci, on l'ajoute à la fin du body
// AppendChild ajoute un élément à la fin de la liste des enfants d'un élément parent
document.body.appendChild(newDiv);

// Soi un tableau d'objets.
const fruits = ['Pomme', 'Banane', 'Orange'];

// Créer une balise <ul> pour la liste
const ul = document.createElement('ul');

// Créer chaque élément de la liste <li> à partir du tableau et les ajouter à la balise <ul>
for (const fruit of fruits) {
    // Créer un <li> 
    const li = document.createElement('li');
    // Remplir le contenu du <li> avec le nom du fruit
    li.textContent = fruit;
    // Ajouter le <li> comme enfant à la balise <ul>
    ul.appendChild(li);
}

// Rendu ici, la balise <ul> contient déjà tous les <li> créés à partir du tableau. Mais elle n'est pas encore "ajoutée" à la page web (DOM). 
// On l'ajoute à la page web (DOM) en l'ajoutant à un élément parent, par exemple le body
document.body.appendChild(ul);

Résultat avant

html
<html>
    <head>
        <title>Exemple de création d'éléments</title>
    </head>
    <body>
        
    </body>
</html>

Résultat après

html
<html>
    <head>
        <title>Exemple de création d'éléments</title>
    </head>
<body>
    <div id="div1" class="my-class">Ceci est une nouvelle div créée dynamiquement !</div>
    <ul>
        <li>Pomme</li>
        <li>Banane</li>
        <li>Orange</li>
    </ul>
</body>
</html>

Exemple 2 : AJOUTER des balises à un endroit précis dans la page web

Interface HTML/ CSS de départ :

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Page Web Complète</title>
</head>
<body>
    <header>
       <h1>Logo</h1>
       <button id="btn1">OK</button>
    </header>
    <nav>
        <ul>
            <li><a href="#">Page 1</a></li>
            <li><a href="#">Page 2</a></li>
        </ul>
    </nav>
    <main id="content">
        <h2>Bienvenue sur ma page web</h2>
        <!-- ON VEUT AJOUTER UN PARAGRAPHE ICI -->
    </main>
</body>
</html>
css
/* Styles de base pour la page web */
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

.rouge
{
    color: red;
}

Javascript :

Ajouter un paragraphe juste après le h2 du main. Il faudra :

  • Créer un nouvel élément <p> avec createElement
  • Remplir le contenu du paragraphe avec textContent
  • Récupérer avec getElementById l'endroit où l'on veut ajouter le paragraphe (à la fin du main dans ce cas)
  • Ajouter le paragraphe à la page web (DOM) à l'endroit désiré
javascript
// Créer un nouvel élément <p>
let newParagraph = document.createElement("p");
newParagraph.textContent = "Ceci est un nouveau paragraphe.";
newParagraph.classList.add("rouge");

// Sélectionner l'élément de référence (parent) dans lequel on veut insérer le nouveau paragraphe
let mainContent = document.getElementById("content");

// Ajouter le nouveau paragraphe à la fin du main
// Ceci va l'ajouter vraiment à la fin du main. Donc si il y avait d'autres éléments après le h2, le nouveau paragraphe serait ajouté après tous les autres éléments du main.
mainContent.appendChild(newParagraph);

function gererClick() {
    // Créer un nouvel élément <p>
    let newParagraph = document.createElement("p");
    newParagraph.textContent = "Ceci est un nouveau paragraphe ajouté au clic.";
    newParagraph.classList.add("rouge");

    // Sélectionner l'élément de référence (parent) dans lequel on veut insérer le nouveau paragraphe
    let mainContent = document.getElementById("content");

    // Ajouter le nouveau paragraphe à la fin du main
    mainContent.appendChild(newParagraph);
}

function initialisation() {

    // Récupérer le bouton et lui ajouter un écouteur d'événement pour gérer les clics. 
    let btnAjouter = document.getElementById("btn1");
    btnAjouter.addEventListener('click', gererClick);
  
}

addEventListener('load', initialisation);

Exemple 3 : REMPLACER du HTML existant à un endroit précis dans la page web

Même Interface HTML/ CSS de départ

Javascript :

On veut remplacer le contenu du main (tout ce qui est à l'intérieur du main) par un nouveau contenu.

Il faudra :

  • Créer les nouveaux éléments à ajouter (ex : un h2 et un p)
  • Récupérer avec getElementById l'endroit où l'on veut ajouter le nouveau contenu (le main dans ce cas)
  • Vider le contenu actuel du main (ex : en mettant innerHTML à une chaîne vide)
  • Ajouter les nouveaux éléments au main, dans l'ordre souhaité (ex : d'abord le h2, puis le p)
javascript
function gererClick() {
    // Se brancher sur l'élément parent dans lequel on veut remplacer le contenu
    let mainContent = document.getElementById("content");

    // Vider le contenu actuel du main
    mainContent.innerHTML = "";

    // Créer le nouveau contenu à ajouter
    let h2 = document.createElement("h2");
    h2.textContent = "Nouveau titre";

    let p = document.createElement("p");
    p.textContent = "Ceci est un nouveau paragraphe qui remplace l'ancien contenu du main.";
    p.classList.add("rouge");

    // Ajouter le nouveau contenu au main, dans l'ordre souhaité
    mainContent.appendChild(h2); // <h2> Nouveau titre </h2> 
    mainContent.appendChild(p); // <p class="rouge"> Ceci est un nouveau paragraphe qui remplace l'ancien contenu du main.</p>
}

function initialisation() {
    // Récupérer le bouton et lui ajouter un écouteur d'événement pour gérer les clics. 
    let btnAjouter = document.getElementById("btn1");
    btnAjouter.addEventListener('click', gererClick);
}

addEventListener('load', initialisation);

Points importants

  • Toujours créer l'élément avec createElement avant de l'ajouter
  • Utiliser appendChild pour insérer l'élément dans le DOM
  • On peut ajouter plusieurs classes avec classList.add()
  • On peut insérer dans n'importe quel élément du DOM

3 : Validation avec expressions régulières

Définition

Les expressions régulières (regex) permettent de vérifier si une chaîne de caractères respecte un motif précis. Elles sont très utilisées pour valider des champs de formulaire (ex : courriel, mot de passe, etc.).

Contexte d’utilisation

On utilise les regex pour valider des données complexes, comme les adresses courriel, numéros de téléphone, etc., avant de les envoyer au serveur.

Avantages des expressions régulières

AvantageDescription
PrécisionValidation exacte selon des motifs complexes
PerformanceVérification rapide côté client
RéutilisabilitéMotifs applicables à plusieurs champs
RobustesseDétection d'erreurs avant soumission
PersonnalisationAdaptation aux besoins spécifiques

Exemples pratiques

javascript
function validateEmail() {
  const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  const emailInput = document.getElementById('email');
  const emailValue = emailInput.value;
  
  if (emailRegex.test(emailValue)) {
    emailInput.classList.remove('error');
    return true;
  } else {
    emailInput.classList.add('error');
    return false;
  }
}

document.getElementById('email').addEventListener("input", validateEmail);

Types de regex courantes

TypeExempleDescription
Email/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/Adresse email valide
Téléphone`/^(+330)1-9$/`
Code postal/^\d{5}$/Code postal français
Mot de passe/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/Au moins 8 caractères, maj, min, chiffre
URL/^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/URL valide

Bonnes pratiques pour les regex

javascript
// ✅ Bonne pratique : utiliser des variables pour la lisibilité
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (emailPattern.test(email)) {
    // valide
}

// ❌ À éviter : regex en ligne difficile à maintenir
if (/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) {
    // valide
}

Points importants

  • Utiliser des sites comme regexr.com pour tester vos regex
  • Toujours tester la regex avec plusieurs cas (valides et invalides)
  • Combiner avec classList pour l'indication visuelle d'erreur
  • Utiliser input pour validation en temps réel

4 : Manipuler des tableaux d'objets et les générer dans le DOM

Définition

Les tableaux et objets permettent de stocker et manipuler des collections de données. On peut ensuite parcourir ces structures pour générer dynamiquement du contenu HTML.

Contexte d’utilisation

Très utile pour afficher des listes, des tableaux, des cartes, etc., à partir de données dynamiques (ex : résultats d'une API, catalogue de produits, etc.).

Exemples pratiques

javascript
// Exemple d'une source de données (tableau d'objets) qui contient 3 utilisateurs avec leurs propriétés nom, age et ville
// Cette variable est globale. Elle peut être utilisée dans n'importe quelle fonction du script.
const utilisateurs = [
  {
    nom: "Alice",
    age: 25,
    ville: "Paris"
  },
  {
    nom: "Bob",
    age: 30,
    ville: "Lyon"
  },
  {
    nom: "Charlie",
    age: 22,
    ville: "Marseille"
  }
];

function genererListeUtilisateurs() {
    let container = document.getElementById('users-container');
    let ul = document.createElement("ul");

    for (let user of utilisateurs) {
      let li = document.createElement("li");
      li.textContent = `${user.nom} (${user.age} ans) - ${user.ville}`;
      ul.appendChild(li);
    }
    container.appendChild(ul);
}
function initialisation() {
    // Appeler la fonction pour générer la liste des utilisateurs à partir du tableau d'objets
    genererListeUtilisateurs();
}
addEventListener('load', initialisation);

Résultat HTML attendu

html
<div id="users-container">
    <ul>
        <li>Alice (25 ans) - Paris</li>
        <li>Bob (30 ans) - Lyon</li>
        <li>Charlie (22 ans) - Marseille</li>
    </ul>
</div>

Points importants

  • Utiliser for, for...of, ou map pour parcourir les tableaux
  • Créer les éléments avec createElement et remplir avec textContent ou innerHTML
  • Toujours ajouter les éléments au DOM avec appendChild ou insertBefore

Exercices pratiques

Exercice 1 : Validation de formulaire et gestion d'utilisateurs (Intermédiaire)

Énoncé

Créer une page web interactive avec un formulaire de connexion comportant deux champs : pseudo et mot de passe. Implémenter une validation en temps réel des champs avec des classes CSS pour la rétroaction visuelle. Lorsque le formulaire est valide, ajouter l'utilisateur à un tableau en mémoire (maximum 5 utilisateurs). Ajouter un bouton pour afficher la liste des utilisateurs enregistrés.

Consignes

  1. Compléter le formulaire de départ avec :

    • Un champ input de type "text" pour le pseudo (id="pseudo")
    • Un champ input de type "password" pour le mot de passe (id="password")
    • Un bouton de soumission (id="submitBtn")
    • Ce formulaire doit avoir un attribut novalidate pour éviter la validation HTML par défaut et sa soumission par défaut devra être bloquée avec event.preventDefault().
  2. Implémenter, par javascript, la validation en temps réel des champs :

    • Le pseudo doit contenir au moins 6 caractères
    • Le mot de passe doit contenir au moins 8 caractères et commencer par le symbole "$"
    • Utiliser des classes CSS "valid" et "invalid" pour la rétroaction visuelle
  3. Gérer un tableau d'utilisateurs en mémoire :

    • Ce tableau, créé globalement, servira à y ajouter, au fur et à mesure, les utilisateurs validés (à la fin de la fonction qui gère le clic du bouton de soumission)
    • Chaque élément du tableau doit être un objet utilisateur avec les propriétés "pseudo" et "password"
    • Limite maximale : 5 utilisateurs
      • Empêcher l'ajout si le tableau est plein et afficher un alert() en conséquence
  4. Utiliser le bouton "Afficher utilisateurs" (id="showUsersBtn") qui devrait :

    • Génèrer dynamiquement une liste à puce dans la page, à un endroit réservé à cet effet (div id="usersList")
      • Format : "Pseudo : Mot de passe" pour chaque utilisateur
    • Remplacer le contenu de la div existante "usersList" à chaque fois que le bouton est cliqué

Structure HTML attendue

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Exercice 1 - Validation Formulaire</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <main>
        <h1>Formulaire d'inscription</h1>
        
        <form id="userForm" novalidate>
          <!-- Champs... -->
          <!-- Bouton de soumission... -->
        </form>
        
        <!-- Bouton pour afficher les utilisateurs -->
        <button id="showUsersBtn">Afficher les utilisateurs</button>
        
        <!-- Zone pour afficher la liste des utilisateurs -->
        <div id="usersList"></div>
    </main>
    
    <script src="script.js"></script>
</body>
</html>

Exercice 2 : Création d'un menu de navigation dynamique (Facile)

Énoncé

À partir d'une page web vide qui contient déjà une structure header, nav, main et footer, créer dynamiquement un menu de navigation simple avec 3 éléments et l'insérer à l'intérieur de la balise <nav> qui possède déjà un ID.

Consignes

  1. Associer un événement click sur le bouton btn1. C'est dans cet événement que la création de l'intérieur du menu de navigation (#2) doit être effectuée.
  2. Créer les éléments HTML suivants à l'aide de JavaScript :
    • Une liste <ul> contenant 3 éléments <li>
    • Chaque <li> contient un lien <a> avec du texte (ex: Accueil, À propos, Contact)
    • Chaque lien a un ID unique et la classe CSS "lien"
  3. Insérer cette structure à l'intérieur de la balise <nav> (qui a déjà un ID dans le HTML)
  4. Utiliser createElement, textContent, classList.add, setAttribute et appendChild dans l'ordre approprié pour construire et insérer les éléments dans le DOM au bon endroit.

Code HTML de base de la page

html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>Menu Dynamique</title>
</head>
<body>
    <header>
        <h1>Mon Site Web</h1>
    </header>
    <nav id="mainNav">
        <p>NAVIGATION À MODIFIER</p>
    </nav>
    <main>
        <h2>Contenu principal</h2>
        <p>Contenu de la page...</p>
        <button id="btn1">Ajouter un paragraphe</button>
    </main>
    <footer>
        <p>Pied de page</p>
    </footer>
    <script src="script.js"></script>
</body>
</html>

Structure HTML à créer dynamiquement

html
<ul>
    <li><a href="#" id="accueil" class="lien">Accueil</a></li>
    <li><a href="#" id="apropos" class="lien">À propos</a></li>
    <li><a href="#" id="contact" class="lien">Contact</a></li>
</ul>

Résultat HTML attendu

html

<!-- Avant le clic sur le bouton : -->
<nav id="mainNav">
    <p>NAVIGATION À MODIFIER</p>
</nav>

<!-- Après le clic sur le bouton: -->
<nav id="mainNav">
    <ul>
        <li><a href="#" id="accueil" class="lien">Accueil</a></li>
        <li><a href="#" id="apropos" class="lien">À propos</a></li>
        <li><a href="#" id="contact" class="lien">Contact</a></li>
    </ul>
</nav>

Vérifications des connaissances

Testez vos connaissances acquises dans ce cours en répondant aux questions suivantes. Cliquez sur chaque question pour révéler la réponse.

Question 1

Quelle méthode permet de créer un nouvel élément HTML en JavaScript ?

Réponse

createElement()

Question 2

Comment ajouter une classe CSS à un élément en JavaScript ?

Réponse

Avec element.classList.add("nomDeClasse")

Question 3

À quoi sert la méthode test() d'une expression régulière ?

Réponse

Elle vérifie si une chaîne correspond au motif de la regex et retourne true ou false.

Question 4

Comment générer dynamiquement une liste HTML à partir d'un tableau d'objets ?

Réponse

En parcourant le tableau avec une boucle, en créant les éléments avec createElement, en remplissant avec textContent puis en ajoutant au DOM avec appendChild.

Question 5

Comment vérifier si un élément possède une classe spécifique ?

Réponse

Avec element.classList.contains('nomDeClasse') qui retourne true si la classe est présente.

Question 6

Quelle méthode permet de basculer (ajouter/retirer) une classe CSS ?

Réponse

element.classList.toggle('nomDeClasse')