Formation publique · Jour 3 / 6

DOM manipulation

Sections

  1. 01 Sélection d’éléments (50 min)
  2. 02 Lire et écrire le DOM (60 min)
  3. 03 Créer, insérer et supprimer (60 min)
  4. 04 Intégration pratique (45 min)
  5. Extra 1 jQuery – lire le code des années 2010 (60 min)
  6. Récap Faire évoluer l’application de notes

1 Sélection d’éléments (50 min)

Objectif : pouvoir pointer n’importe quel élément de la page depuis le JavaScript et depuis la Console, et comprendre que le panneau Elements est la représentation live de l’arbre.

1.1 Le DOM est un arbre live

Le navigateur construit un arbre d’objets à partir du HTML.

Cet arbre s’appelle le DOM (Document Object Model).

Le panneau Elements des DevTools affiche exactement cet arbre, en direct.

document

document est la racine. Tout part de là.

1.2 querySelector – un seul élément

const status = document.querySelector('#reactor-status');
console.log(status);
const firstRod = document.querySelector('.control-rod');
console.log(firstRod);
const scramBtn = document.querySelector('button#scram');
console.log(scramBtn);

Si rien ne correspond, querySelector retourne null.

1.3 querySelectorAll – une collection

const rods = document.querySelectorAll('.control-rod');
console.log(rods);          // NodeList
console.log(rods.length);
console.log(rods[0]);

querySelectorAll retourne une NodeList statique.

1.4 Sélecteurs CSS indispensables

document.querySelector('#power-mw')             // id
document.querySelector('.alarm')                // class
document.querySelector('h2')                    // balise
document.querySelector('[data-unit="C"]')       // attribut
document.querySelector('.panel .gauge')         // descendant
document.querySelector('.panel > .gauge')       // enfant direct
document.querySelector('.control-rod:first-child')
document.querySelector('.control-rod:nth-child(2)')

Vous n’avez pas besoin de plus pour l’instant.

1.5 Le raccourci Console : $0

Ouvrez le panneau Elements.

Cliquez sur un élément.

Dans la Console tapez :

$0

$0 est l’élément actuellement sélectionné dans Elements.

1.6 Méthodes historiques (juste pour les reconnaître)

document.getElementById('reactor-status')
document.getElementsByClassName('control-rod')  // HTMLCollection live
document.getElementsByTagName('button')

On préfère systématiquement querySelector / querySelectorAll.

1.7 NodeList vs HTMLCollection (point de vigilance)

const list1 = document.querySelectorAll('.control-rod');     // NodeList (statique)
const list2 = document.getElementsByClassName('control-rod'); // HTMLCollection (live)

Une collection live se met à jour automatiquement.

Une NodeList obtenue avec querySelectorAll ne le fait pas.

Restez sur querySelectorAll pour l’instant.

À essayer

Checkpoint
Vous savez :

  • sélectionner un élément avec querySelector,
  • sélectionner plusieurs éléments avec querySelectorAll,
  • utiliser $0 depuis la Console,
  • expliquer pourquoi on préfère les sélecteurs modernes.

2 Lire et écrire le DOM (60 min)

Vous savez sélectionner. Maintenant vous lisez et vous modifiez.

2.1 Lire et écrire du texte – textContent

La propriété la plus simple et la plus sûre pour le texte visible.

const status = document.querySelector('#reactor-status');
console.log(status.textContent);   // lecture

status.textContent = 'SURVEILLANCE'; // écriture

2.2 textContent vs innerHTML

textContent traite toujours la chaîne comme du texte brut.

el.textContent = '<b>ALERTE</b>'; // affiche les caractères <b>…</b>

innerHTML interprète les balises HTML.

el.innerHTML = '<b>ALERTE</b>'; // affiche ALERTE en gras

Règle simple : préférez textContent. N’utilisez innerHTML que lorsque vous devez vraiment injecter du HTML, et seulement si la source est contrôlée.

2.3 Attributs

const rod = document.querySelector('.control-rod');
rod.getAttribute('data-rod');           // lecture
rod.setAttribute('title', 'Barre 1');   // écriture
rod.removeAttribute('data-rod');        // suppression
rod.hasAttribute('title');              // true / false

2.4 dataset – les data-*

Les attributs data-* sont exposés via la propriété dataset.

const mode = document.querySelector('#operation-mode');
console.log(mode.dataset.mode);  // "normal"
mode.dataset.mode = 'test';

data-rod devient dataset.rod. data-unit-type devient dataset.unitType (camelCase).

2.5 Propriétés directes

Certains attributs ont une propriété miroir plus pratique.

const btn = document.querySelector('#scram');
btn.disabled = true;    // équivalent à setAttribute('disabled', '')
btn.disabled = false;

Autres propriétés courantes : id, value, href, checked, hidden…

2.6 classList – la façon moderne de gérer les classes

const status = document.querySelector('#reactor-status');
status.classList.add('status-warning');
status.classList.remove('status-ok');
status.classList.toggle('status-critical');
status.classList.contains('status-warning'); // true / false
status.classList.replace('status-warning', 'status-critical');

Ne touchez plus à className = "…" sauf cas très particulier.

2.7 style (inline) – à utiliser avec parcimonie

const temp = document.querySelector('#temp-value');
temp.style.color = 'red';
temp.style.color = '';          // annule le style inline

Les styles inline ont la priorité la plus haute. Préférez classList + feuilles de style dans 95 % des cas.

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-3/s2_read-write

Travaillez uniquement dans scripts.js. Suivez les commentaires dans l’ordre. Après chaque bloc : sauvegardez → rafraîchissez → regardez la Console et le panneau Elements.

Checkpoint

Vous savez :

  • lire et écrire du texte avec textContent,
  • manipuler les attributs et dataset,
  • ajouter / retirer / basculer des classes avec classList,
  • expliquer pourquoi on évite innerHTML et les styles inline par défaut.

3 Créer, insérer et supprimer (60 min)

Jusqu’ici vous modifiiez des éléments déjà présents. Maintenant vous en créez, vous les placez, vous les retirez.

3.1 createElement

Crée un élément en mémoire. Il n’apparaît pas encore dans la page.

const el = document.createElement('div');
el.className = 'log-entry';
el.textContent = '[09:15:00] Test';

3.2 L’erreur classique

Vous créez l’élément. Vous le voyez dans la Console. Il n’est toujours pas dans le panneau Elements.

console.log(el); // l’objet existe
// Mais rien n’a changé dans la page.

createElement ne l’insère pas. C’est volontaire.

3.3 append et prepend

append et prepend insèrent un élément à l’intérieur d’un parent. append le place comme dernier enfant ; prepend comme premier enfant.

const container = document.querySelector('#log-container');
container.append(el);     // à la fin
container.prepend(el);    // au début

3.4 before et after

before et after insèrent un élément à côté de l’élément de référence, dans le même parent. Le nouvel élément devient donc un élément frère (sibling), juste avant ou juste après la référence.

const reference = document.querySelector('#alarm-pressure');
const newAlarm = document.createElement('div');
newAlarm.className = 'alarm';
newAlarm.textContent = 'Température secondaire';

reference.after(newAlarm);   // juste après
reference.before(newAlarm);  // juste avant

3.5 remove

remove retire directement l’élément du DOM. On appelle la méthode sur l’élément à supprimer : il est détaché de son parent.

const az5 = document.querySelector('#alarm-az5');
az5.remove();

3.6 replaceWith

replaceWith remplace l’élément de référence par un autre élément, au même emplacement dans le parent. Le nouvel élément prend sa place parmi les mêmes éléments frères (siblings).

const critical = document.createElement('div');
critical.className = 'alarm';
critical.textContent = 'Pression critique – AZ-5 demandé';

document.querySelector('#alarm-pressure').replaceWith(critical);

3.7 Créer plusieurs éléments à partir de données

Pattern fréquent : un tableau d’objets → plusieurs éléments DOM.

const rods = [
  { id: 4, inserted: true },
  { id: 5, inserted: false }
];

rods.forEach(data => {
  const rod = document.createElement('div');
  rod.classList.add('control-rod');
  if (data.inserted) rod.classList.add('inserted');
  rod.dataset.rod = data.id;

  const label = document.createElement('span');
  label.textContent = data.id;
  rod.append(label);

  document.querySelector('#rods-container').append(rod);
});

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-3/s3_create-insert

Travaillez uniquement dans scripts.js. Suivez les commentaires dans l’ordre. Après chaque bloc : sauvegardez → rafraîchissez → regardez la Console et le panneau Elements.

Checkpoint

Vous savez :

  • créer un élément avec createElement,
  • l’insérer avec append / prepend / before / after,
  • le retirer avec remove et le remplacer avec replaceWith,
  • construire plusieurs éléments à partir d’un tableau de données,
  • expliquer pourquoi un élément fraîchement créé n’apparaît pas tout seul dans la page.

4 Intégration pratique (45 min)

Pas de nouvelle API. On combine tout ce qui a été vu aujourd’hui : sélection, lecture/écriture, création, insertion, suppression.

À chaque étape le réflexe est le même :

1. Modifier le code
2. Sauvegarder + rafraîchir
3. Vérifier dans Elements
4. Vérifier dans la Console
5. Si c’est faux → breakpoint dans Sources

4.1 Scénario 1 – Mise en surveillance

Le réacteur passe en mode surveillance.

const status = document.querySelector('#reactor-status');
status.textContent = 'SURVEILLANCE';
status.classList.remove('status-ok');
status.classList.add('status-warning');
document.querySelector('#status-light').classList.add('warning');
document.querySelector('#power-mw').textContent = '2950';

4.2 Scénario 2 – Nouvelle alarme + journal

Créer un élément, l’insérer, puis tracer l’action dans le journal.

const alarm = document.createElement('div');
alarm.className = 'alarm';
alarm.textContent = 'Température sortie élevée';
document.querySelector('#alarms-container').append(alarm);
const entry = document.createElement('div');
entry.className = 'log-entry';
entry.textContent = '[09:12:44] Alarme température créée';
document.querySelector('#log-container').append(entry);

4.3 Scénario 3 – Nettoyage

document.querySelector('#alarm-az5').remove();

const btn = document.querySelector('#scram');
btn.disabled = true;
btn.setAttribute('title', 'SCRAM verrouillé – procédure en cours');

4.4 Scénario 4 – Données → DOM

Construire plusieurs éléments à partir d’un tableau (révision de la section 3).

const extraRods = [
  { id: 5, inserted: false },
  { id: 6, inserted: true }
];

extraRods.forEach(data => {
  const rod = document.createElement('div');
  rod.classList.add('control-rod');
  if (data.inserted) rod.classList.add('inserted');
  rod.dataset.rod = data.id;

  const label = document.createElement('span');
  label.textContent = data.id;
  rod.append(label);

  document.querySelector('#rods-container').append(rod);
});

4.5 Scénario 5 – Contrôle final avec DevTools

Utilisez la Console pour vérifier l’état final.

document.querySelectorAll('.alarm').forEach(a => console.log(a.textContent));
console.log(document.querySelectorAll('.control-rod').length);
console.log(document.querySelector('#operation-mode').dataset.mode);

Si une valeur est incorrecte : ouvrez Sources, posez un breakpoint sur la ligne fautive, rejouez.

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-3/s4_integration

Travaillez uniquement dans scripts.js. Suivez les scénarios dans l’ordre. Après chaque scénario : Elements → Console → Sources si besoin.

Checkpoint

Vous savez enchaîner sélection + modification + création + insertion + suppression sur un même écran, et vous utilisez systématiquement Elements, Console et Sources pour vérifier.

x1 jQuery – lire le code des années 2010 (60 min)

Vous venez d’apprendre à manipuler le DOM à la main. C’est bien.

Vous voulez voir une version nettement plus confortable, introduite au début des années 2010 ?

Oui… personne ne manipule le DOM à la main en 2026, sauf hobby tordu ou mauvaise décision de management (« notre CISO a dit qu’on ne pouvait pas utiliser de bibliothèques tierces, trop risqué, donc on code à la main… lol, en 2026 qui fait encore ça »).

Pourtant vous allez rencontrer jQuery dans d’innombrables bases legacy. Savoir le lire est une compétence professionnelle. Savoir quand ne plus l’utiliser aussi.

x1.1 Pourquoi jQuery a existé

2006–2015 : les navigateurs étaient inconsistants. Sélectionner un élément, gérer les événements, faire de l’Ajax simple était pénible et différent selon IE, Firefox, Chrome…

jQuery a unifié tout ça derrière une API courte et chaînable. Pendant dix ans, « savoir jQuery » voulait dire « savoir le front ».

Aujourd’hui les navigateurs sont alignés et le JS natif a rattrapé (querySelector, classList, fetch, addEventListener…). Pour du code neuf on reste en vanilla. Pour du code ancien on doit comprendre jQuery.

x1.2 Charger jQuery

Dans cet extra uniquement, la page charge jQuery depuis un CDN :

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

Ensuite $ et jQuery sont disponibles.

typeof $        // "function"
typeof jQuery   // "function"

x1.3 Sélection

$('#reactor-status')        // équivalent de document.querySelector('#reactor-status')
$('.control-rod')           // équivalent de document.querySelectorAll('.control-rod')
$('.control-rod').length

Le résultat est un objet jQuery (une collection), pas un élément DOM brut.

x1.4 Texte et HTML

$('#reactor-status').text()                 // lecture
$('#reactor-status').text('SURVEILLANCE')   // écriture
$('#power-mw').text('2800')
$el.text('<b>ALERTE</b>')   // texte brut (comme textContent)
$el.html('<b>ALERTE</b>')   // interprète le HTML (comme innerHTML)

Même règle de prudence qu’en vanilla : préférez .text() par défaut.

x1.5 Classes

$('#reactor-status')
  .removeClass('status-ok')
  .addClass('status-warning');

$('#reactor-status').toggleClass('status-critical');
$('#reactor-status').hasClass('status-warning')   // true / false

x1.6 Attributs, data, propriétés

$('.control-rod').first().attr('data-rod')     // lecture d’attribut
$('#operation-mode').attr('data-mode', 'test') // écriture
$('#scram').prop('disabled', true)             // propriété booléenne

x1.7 Créer et insérer

const $alarm = $('<div class="alarm">Température secondaire</div>');
$('#alarms-container').append($alarm);

$('<div class="log-entry">[09:30:00] Ajout via jQuery</div>')
  .appendTo('#log-container');

x1.8 Le chaînage – signature de jQuery

$('#reactor-status')
  .text('CRITIQUE')
  .removeClass('status-ok status-warning')
  .addClass('status-critical');

Une seule expression, plusieurs opérations. C’était l’argument de vente principal.

x1.9 Événement (aperçu)

$('#scram').on('click', function () {
  console.log('SCRAM demandé via jQuery');
  $(this).text('SCRAM ENGAGÉ');
});

Équivalent moderne : element.addEventListener('click', …). On reverra les événements en détail au Jour 4, en vanilla.

x1.10 Vanilla ↔ jQuery – table de correspondance

document.querySelector('#id')          ≈  $('#id')
document.querySelectorAll('.cls')      ≈  $('.cls')
el.textContent = '…'                   ≈  $el.text('…')
el.classList.add('x')                  ≈  $el.addClass('x')
el.classList.remove('x')               ≈  $el.removeClass('x')
el.setAttribute('a', 'v')              ≈  $el.attr('a', 'v')
el.disabled = true                     ≈  $el.prop('disabled', true)
createElement + append                 ≈  $('<div>…</div>').appendTo(…)
el.addEventListener('click', fn)       ≈  $el.on('click', fn)

Règle de fin de section : pour du code neuf en 2026, restez en vanilla. Pour lire ou maintenir un vieux projet, jQuery doit être lisible pour vous.

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-3/x1_jquery

Travaillez uniquement dans scripts.js. jQuery est déjà chargé. Suivez les commentaires dans l’ordre. Après chaque bloc : sauvegardez → rafraîchissez → Console + Elements.

Checkpoint

Vous savez :

  • sélectionner avec $(),
  • lire/écrire du texte et des classes,
  • créer et insérer des éléments,
  • reconnaître le style chaîné,
  • faire la correspondance mentale vanilla ↔ jQuery,
  • expliquer pourquoi on n’introduit plus jQuery dans un projet neuf.

Récap — Faire évoluer l’application de notes

Terminez la journée en faisant évoluer l’application de notes avec les manipulations du DOM vues aujourd’hui.

Ouvrez le dossier Day3_redux dans le dépôt js-extra.

Choisissez une ou plusieurs fonctionnalités à explorer :

  1. Supprimer une note.
  2. Modifier le titre et le contenu de la note sélectionnée.
  3. Épingler ou désépingler une note.
  4. Afficher en direct le nombre total de notes.
  5. Afficher en direct le nombre de notes épinglées.
  6. Filtrer toutes les notes ou seulement les notes épinglées.
  7. Rechercher en direct dans les titres.
  8. Trier les notes par updatedAt, de la plus récente à la plus ancienne.
  9. Exporter toutes les notes au format JSON.
  10. Importer un fichier JSON en fusionnant les notes avec les notes existantes.
  11. Effacer toutes les notes après confirmation avec window.confirm().
  12. Mémoriser selectedId dans sessionStorage.

Utilisez Elements, la Console et Sources pour observer chaque modification. Le but est d’explorer le code et de comprendre le flux, pas de terminer obligatoirement les douze fonctionnalités.