Manipuler le contenu textuel du DOM
Présentation
Une fois un élément sélectionné dans le DOM, la suite consiste souvent à lire une information affichée dans la page ou à la modifier. Cela peut servir à afficher un message, mettre à jour un compteur, remplacer un texte après une action, ou synchroniser une donnée entre plusieurs éléments.
JavaScript propose plusieurs façons d'accéder au contenu d'une balise. Ces approches ne renvoient pas exactement la même chose, car elles ne se basent pas sur la même notion de contenu. Certaines travaillent sur du texte brut, d'autres sur ce qui est réellement visible, d'autres encore manipulent directement du HTML.
L'objectif de cette page consiste à apprendre à choisir la bonne propriété selon le besoin. Dans un premier temps, l'accent est mis sur textContent, car c'est la solution la plus simple et la plus sûre pour afficher une chaîne. Ensuite, une comparaison avec innerText et innerHTML permet de comprendre les différences. Enfin, un cas particulier est abordé, les champs de formulaire, qui utilisent la propriété value.
Règle de base Dès qu'une chaîne provient d'une source non totalement maîtrisée (saisie utilisateur, paramètres d'URL, réponse d'API, contenu stocké dans localStorage, etc.), l'affichage doit se faire avec textContent. Cela empêche l'interprétation de HTML et réduit fortement le risque d'injection.
Manipuler le texte d'une balise
JavaScript met à disposition plusieurs propriétés permettant de lire ou de modifier le texte situé entre les balises. Dans un premier temps, l'approche recommandée consiste à utiliser textContent, car elle manipule du texte brut sans interpréter du HTML.
Lire et modifier du texte avec textContent
La propriété textContent permet d'accéder au texte contenu dans une balise. Elle travaille avec du texte brut. Cela signifie que le navigateur n'interprète pas la chaîne comme du HTML. Dès qu'une simple chaîne doit être affichée, textContent constitue le choix le plus sûr.
Lire le texte d'une balise
Dans l'exemple suivant, une balise p est sélectionnée, puis son texte est lu via textContent.
Code HTML :
<p id="paragrapheSimple">Bonjour tout le monde</p>
Code Javascript :
// Cibler la balise "p" dont l'attribut "id" vaut "paragrapheSimple".
const paragrapheElem = document.querySelector('#paragrapheSimple');
// Bonne pratique, vérifier la sélection.
if (paragrapheElem === null)
{
console.log("Élément introuvable.");
}
else
{
// Lire le texte contenu dans la balise.
console.log(paragrapheElem.textContent); // Affiche "Bonjour tout le monde"
}
Modifier le texte d'une balise
Pour modifier le texte, il suffit d'affecter une nouvelle valeur à textContent. Le navigateur met à jour la page immédiatement.
Dans l'exemple suivant, le texte affiché dans la balise p est remplacé.
Code HTML :
<p id="paragrapheSimple">Bonjour tout le monde</p>
Code Javascript :
const paragrapheElem = document.querySelector('#paragrapheSimple');
// Toujours vérifier la sélection.
if (paragrapheElem !== null)
{
// Remplacer le texte de la balise.
paragrapheElem.textContent = "Je s'appelle Groot!";
}
Résultat dans le navigateur après exécution du script :
Je s'appelle Groot!
Si une chaîne contenant des balises HTML est affectée à textContent, ces balises ne sont pas interprétées. Elles sont affichées comme du texte. Cette propriété évite ainsi une grande partie des problèmes liés à l'injection de contenu.
Code Javascript :
const paragrapheElem = document.querySelector('#paragrapheSimple');
if (paragrapheElem !== null)
{
// Les balises ne seront pas interprétées, elles seront affichées comme du texte.
paragrapheElem.textContent = "<span>Je s'appelle Groot!</span>";
}
Résultat dans le navigateur après exécution du script :
<span>Je s'appelle Groot!</span>
Les chevrons ne sont pas interprétés comme des balises HTML. L'utilisation de textContent force l'insertion du contenu sous forme de texte brut, ce qui provoque l'échappement des caractères spéciaux. Si le code source de la page est observé dans le navigateur, le segment ajouté apparaît donc encodé sous forme d'entités HTML.
Extrait du code source correspondant dans le navigateur :
<p id="paragrapheSimple"><span>Je s'appelle Groot!</span></p>
Mettre à jour un petit texte sans toucher au reste
Lorsque seule une petite information doit être mise à jour, un ciblage précis est préférable. Une balise dédiée au compteur ou au message évite de remplacer un bloc complet.
Code HTML :
<p>Messages non lus <span id="compteurMessages">0</span></p>
Code Javascript :
const compteurElem = document.querySelector('#compteurMessages');
if (compteurElem === null)
{
console.log("Compteur introuvable.");
}
else
{
// Simuler une mise à jour de compteur.
const nouveauNombre = 3;
// Ici, textContent est adapté car il s'agit d'un affichage simple.
compteurElem.textContent = String(nouveauNombre);
}
Comparer textContent, innerText et innerHTML
textContent est souvent suffisant pour manipuler du texte. Cependant, selon le résultat attendu, d'autres propriétés existent. Elles ne renvoient pas la même chose et ne servent pas au même usage.
- textContent Lit ou modifie le texte contenu dans une balise. Le contenu est manipulé comme du texte brut, sans interprétation de HTML.
- innerText Lit ou modifie le texte réellement rendu à l'écran. Le résultat dépend du rendu de la page, donc de la mise en forme et du fait que certains éléments soient visibles ou non.
- innerHTML Lit ou modifie le contenu HTML d'une balise. Lors d'une écriture, la chaîne est interprétée comme du code HTML et transforme le DOM. Cette propriété est pratique pour insérer une structure HTML, mais elle doit être utilisée avec prudence.
Dans l'exemple suivant, un paragraphe contient du texte sur plusieurs lignes, ainsi qu'un mot masqué. L'objectif consiste à observer la différence entre le texte brut du DOM, le texte rendu et le code HTML.
Code HTML :
<p id="paragrapheTest">
Mon super
<span style="display: none;">texte</span>
de test !
</p>
Code Javascript :
const monParagraphe = document.querySelector('#paragrapheTest');
if (monParagraphe === null)
{
console.log("Paragraphe introuvable.");
}
else
{
console.log(monParagraphe.textContent);
console.log(monParagraphe.innerText);
console.log(monParagraphe.innerHTML);
/*
textContent renvoie le texte brut du DOM.
Il inclut le texte masqué et conserve des retours à la ligne :
"Mon super
texte
de test !"
innerText renvoie le texte réellement rendu.
Le mot masqué n'apparaît pas et les espaces sont normalisés :
"Mon super de test !"
innerHTML renvoie le HTML interne de la balise :
"Mon super
<span style="display: none;">texte</span>
de test !"
*/
}
Règle de base innerHTML interprète la chaîne fournie comme du HTML. Si la chaîne contient du contenu non fiable, une faille de type XSS peut apparaître. Pour afficher une donnée dont la source n'est pas totalement maîtrisée, textContent reste le choix recommandé.
Il est possible de concaténer du contenu avec innerHTML, par exemple via innerHTML += "...". Cette écriture donne l'impression d'ajouter simplement du contenu, mais elle entraîne en réalité une reconstruction de la sous-arborescence concernée. Des nœuds peuvent être recréés, ce qui peut provoquer la perte d'écouteurs d'événements ajoutés directement sur ces éléments, ainsi que la réinitialisation de certains états.
Pour ajouter du contenu sans reconstruire les nœuds existants, d'autres méthodes existent. Elles seront vues plus tard, dans un chapitre dédié nommé Manipuler la structure du DOM. Le point important ici concerne la sécurité, une insertion HTML ne doit se faire qu'avec du contenu fiable.
Sécurité et bonnes pratiques lors de l'affichage de contenu dynamique
Les règles de cette section s'appliquent à n'importe quel élément du DOM p, div, section, etc. Le point central ne dépend pas du nom de la balise, mais de la façon dont une chaîne est injectée dans la page.
Règle de base Dès qu'une chaîne provient d'une source non totalement maîtrisée (saisie utilisateur, paramètres d'URL, réponse d'API, contenu stocké dans localStorage, fichier chargé, etc.), l'affichage doit se faire avec textContent.
Comprendre le risque XSS de manière concrète
Une attaque XSS consiste à faire interpréter du code par le navigateur à partir d'une chaîne injectée dans la page. Le cas typique apparaît lorsqu'une donnée non fiable est insérée via innerHTML. Si la chaîne contient du HTML malveillant, le navigateur peut le traiter comme du vrai DOM.
DO et DON'T avec un exemple minimal
Code HTML :
<p id="sortieSecurite">...</p>
Code Javascript :
const sortieElem = document.querySelector('#sortieSecurite');
if (sortieElem === null)
{
console.log("Élément introuvable.");
}
else
{
// Exemple de donnée non fiable.
const valeurUtilisateur = "<img src=x onerror=alert('XSS')> Bonjour";
// DON'T, dangereux.
// sortieElem.innerHTML = valeurUtilisateur;
// DO, sûr.
sortieElem.textContent = valeurUtilisateur;
}
Ici, textContent affiche la chaîne telle quelle. Le navigateur n'interprète pas les balises. C'est exactement ce qui empêche l'exécution d'un code injecté.
Mettre à jour uniquement le texte, pas tout le bloc
Une bonne pratique consiste à préparer une structure HTML stable, puis à ne modifier que les zones de texte. Cela limite les effets secondaires et évite de dépendre de innerHTML.
Code HTML :
<div id="carteProfil">
<p>Pseudo <span id="carteProfilPseudo">...</span></p>
<p>Bio</p>
<p id="carteProfilBio">...</p>
</div>
Code Javascript :
const pseudoElem = document.querySelector('#carteProfilPseudo');
const bioElem = document.querySelector('#carteProfilBio');
if (pseudoElem === null || bioElem === null)
{
console.log("Carte profil introuvable.");
}
else
{
// Données potentiellement non fiables.
const donnees = {
pseudo: "<img src=x onerror=alert('XSS')>",
bio: "Débutant en JS. J'aime apprendre."
};
// Affichage sûr.
pseudoElem.textContent = donnees.pseudo;
bioElem.textContent = donnees.bio;
}
Quand innerHTML peut être acceptable
innerHTML peut être acceptable uniquement si la chaîne est entièrement maîtrisée par le développeur, donc un gabarit écrit dans le code. Une valeur variable non fiable ne doit jamais être concaténée dans ce gabarit.
Code HTML :
<div id="zoneAideContenu"></div>
Code Javascript :
const contenuElem = document.querySelector('#zoneAideContenu');
if (contenuElem !== null)
{
// Gabarit fiable, écrit par le développeur.
const htmlFiable = '<p>Astuce, utiliser <b>textContent</b> pour afficher une chaîne non fiable.</p>';
// OK car le HTML est totalement maîtrisé.
contenuElem.innerHTML = htmlFiable;
}
Pour construire du HTML à partir de données variables tout en restant sûr, d'autres outils existent comme createElement() et append(). Ils seront vus plus tard dans un chapitre dédié nommé Manipuler la structure du DOM.
Pour aller plus loin
Si une application doit accepter un petit sous-ensemble de HTML, un sanitizer côté client (par exemple DOMPurify) peut nettoyer la chaîne avant insertion. Une protection complémentaire côté navigateur s'appelle Trusted Types. Ces options sont avancées et ne remplacent pas la règle de base une donnée non fiable ne doit pas être interprétée comme du HTML.
Manipuler la valeur d'un champ de formulaire
Les champs de formulaire constituent un cas particulier dans le DOM. Le texte visible dans le champ ne correspond pas forcément à du texte stocké "entre des balises" dans le HTML. Le navigateur maintient un état interne pour chaque champ, et JavaScript lit ou modifie cet état via des propriétés.
-
input de type text, textarea, select, radio
- Propriété utile : value
- Type renvoyé : Chaîne
-
checkbox, radio
- Propriété utile : checked
- Type renvoyé : Booléen
-
input de type number
- Propriété utile : valueAsNumber
- Type renvoyé : Nombre ou NaN
-
input de type date
- Propriété utile : valueAsDate
- Type renvoyé : Date ou null
input de type texte
La valeur interactive d'un champ input de type texte se lit et se modifie via la propriété JavaScript value. La valeur renvoyée est une chaîne.
Code HTML
<label>Nom
<input id="nom" type="text" value="Ada">
</label>
Code JavaScript
const nomInput = document.querySelector('#nom');
// Afficher la valeur interactive du champ.
console.log(nomInput.value); // Affiche: "Ada"
// Remplacer la valeur interactive du champ.
nomInput.value = "Alan";
// Afficher à nouveau la valeur interactive du champ.
console.log(nomInput.value); // Affiche: "Alan"
Ne pas confondre l'attribut value et la propriété value
L'attribut HTML value sert uniquement à définir la valeur initiale du champ. Au chargement de la page, cette valeur est copiée dans la propriété JavaScript value. Ensuite, seule la propriété JavaScript value évolue, tandis que l'attribut HTML reste inchangé.
Une propriété JavaScript defaultValue expose cette valeur par défaut côté DOM. Elle correspond à la valeur définie initialement dans l'attribut HTML value.
const nomInput = document.querySelector('#nom');
// Valeur par défaut (celle définie dans l'attribut HTML "value").
console.log(nomInput.defaultValue); // Affiche: "Ada"
// Afficher la valeur interactive (celle que l'utilisateur voit et modifie).
console.log(nomInput.value); // Affiche: "Ada"
// Remplacer la valeur interactive du champ.
nomInput.value = "Alan";
// La valeur interactive a bien changé.
console.log(nomInput.value); // Affiche: "Alan"
// La valeur par défaut reste inchangée.
console.log(nomInput.defaultValue); // Affiche: "Ada"
textarea
Un textarea contient du texte entre ses balises. Ce texte définit la valeur par défaut au chargement. Ensuite, la valeur interactive se lit et se modifie via la propriété Javascript value, comme pour un input.
Code HTML
<label>Message
<textarea id="message">Bonjour</textarea>
</label>
Code JavaScript
const messageTextarea = document.querySelector('#message');
// Valeur par défaut (celle définie entre les balises HTML <textarea>...</textarea>).
console.log(messageTextarea.defaultValue); // Affiche: "Bonjour"
// Afficher la valeur interactive.
console.log(messageTextarea.value); // Affiche: "Bonjour"
messageTextarea.value = "Salut";
console.log(messageTextarea.value); // Affiche: "Salut"
// La valeur par défaut reste inchangée.
console.log(messageTextarea.defaultValue); // Affiche: "Bonjour"
select
Une liste déroulante select expose le choix courant via value. Pour changer la sélection, assigner à value une valeur portée par une balise option. Si une option ne possède pas d'attribut value, sa valeur correspond à son texte.
Code HTML
<label>Langage
<select id="langage">
<option value="js">JavaScript</option>
<option value="php">PHP</option>
<option value="py">Python</option>
</select>
</label>
Code JavaScript
const langageSelect = document.querySelector('#langage');
console.log(langageSelect.value); // Affiche: "js" (par défaut)
// Remplacer la valeur interactive par une valeur existante parmi les options.
langageSelect.value = "php";
// Afficher la valeur interactive.
console.log(langageSelect.value); // Affiche: "php"
// Remplacer la valeur interactive par une valeur inexistante parmi les options.
langageSelect.value = "ruby";
// Le remplacement précédent ayant échoué, la valeur a été remplacée par une chaîne vide.
console.log(langageSelect.value); // Affiche: ""
input de type checkbox
Une case à cocher représente un état vrai ou faux. La propriété checked reflète cet état. La propriété value existe aussi, mais elle représente surtout la valeur transmise lors d'une soumission de formulaire. Pour savoir si la case est cochée, lire checked.
Code HTML
<label>
<input id="newsletter" type="checkbox" checked>
Recevoir la newsletter
</label>
Code JavaScript
const newsletterCheckbox = document.querySelector('#newsletter');
// La propriété Javascript vaut "true", ce qui signifie que la case est cochée.
console.log(newsletterCheckbox.checked); // Affiche: true
// Décoher la case en remplaçant la valeur interactive par "false".
newsletterCheckbox.checked = false;
input de type radio
Un bouton radio représente un choix parmi plusieurs options. Les radios forment un groupe lorsqu'ils partagent le même attribut HTML name. Dans un groupe, un seul radio peut être coché à la fois.
Code HTML
<p>Niveau</p>
<label>
<input type="radio" name="niveau" value="debutant" checked>
Débutant
</label>
<label>
<input type="radio" name="niveau" value="intermediaire">
Intermédiaire
</label>
<label>
<input type="radio" name="niveau" value="avance">
Avancé
</label>
Pour récupérer le choix actuel, cibler le radio coché avec le sélecteur CSS :checked, puis lire sa propriété value. Si aucun radio n'est coché, la recherche renvoie null.
Code JavaScript
const niveauChecked = document.querySelector('input[name="niveau"]:checked');
if (niveauChecked === null)
{
console.log("Aucun niveau sélectionné");
}
else
{
console.log(niveauChecked.value);
}
La propriété Javascript checked permet de lire ou modifier l'état courant. Passer checked à true sur un radio décoche automatiquement les autres radios du même groupe. Passer checked à false peut laisser le groupe sans sélection, ce qui n'arrive pas via un simple clic sur un radio déjà coché.
Code JavaScript
// Sélectionner le radio du groupe "niveau" dont l'attribut HTML value vaut "intermediaire".
const radioACocher = document.querySelector('input[name="niveau"][value="intermediaire"]');
// Modifier l'état courant du radio via la propriété JavaScript checked.
// Le navigateur décoche automatiquement les autres radios du même groupe.
radioACocher.checked = true;
Ne pas confondre le sélecteur CSS :checked et le sélecteur d'attribut [checked].
:checked sélectionne les radios selon leur état courant, c'est-à-dire l'état réellement actif au moment où le code s'exécute. Cet état correspond à la propriété JavaScript checked.
[checked], en revanche, sélectionne uniquement les radios qui possèdent l'attribut HTML checked. Cet attribut définit la valeur initiale au chargement de la page et ne se met pas à jour automatiquement lorsque l'utilisateur change de sélection.
// Sélection selon l'état courant (ce que l'utilisateur a réellement choisi).
const radioEtatCourant = document.querySelector('input[name="niveau"]:checked');
console.log(radioEtatCourant.value);
// Au chargement, Affiche : "debutant"
// Après sélection de "intermediaire" par l'utilisateur, Affiche : "intermediaire"
// Sélection selon l'attribut HTML checked (valeur définie au chargement).
const radioAttributHTML = document.querySelector('input[name="niveau"][checked]');
console.log(radioAttributHTML.value);
// Au chargement, Affiche : "debutant"
// Après sélection de "intermediaire" par l'utilisateur, Affiche toujours : "debutant"
input de type number
Un champ input de type number stocke toujours une chaîne dans la propriété JavaScript value, même si l'utilisateur saisit un nombre. Cette représentation sous forme de texte complique les traitements et les validations numériques.
Pour obtenir directement un nombre, JavaScript fournit la propriété valueAsNumber. Si le champ est vide ou contient une valeur invalide, valueAsNumber renvoie NaN, ce qui permet de détecter facilement un problème de saisie.
Code HTML
<label>Age
<input id="age" type="number" value="42">
</label>
Code JavaScript
const ageInput = document.querySelector('#age');
console.log(ageInput.value); // Affiche: "42"
const age = ageInput.valueAsNumber;
if (Number.isNaN(age))
{
console.log("Aucune valeur numérique valide");
}
else
{
console.log(age); // Affiche: 42
}
input de type date
Un champ input de type date expose toujours une chaîne dans la propriété JavaScript value, au format YYYY-MM-DD. Cette chaîne est pratique pour enregistrer ou transmettre une date.
JavaScript fournit également la propriété valueAsDate, qui renvoie un objet Date. Si le champ est vide ou invalide, valueAsDate renvoie null. Cette propriété est utile lorsque des calculs ou des comparaisons de dates sont nécessaires.
Code HTML
<label>Date de naissance
<input id="naissance" type="date" value="1990-12-01">
</label>
const naissanceInput = document.querySelector('#naissance');
// Afficher la valeur interactive via la propriété value
// pour observer le format renvoyé (chaîne YYYY-MM-DD).
console.log(naissanceInput.value); // Affiche: "1990-12-01"
// Lire la date sous forme d'objet Date.
// Si aucun choix n'a été fait, valueAsDate renvoie null.
const dateNaissance = naissanceInput.valueAsDate;
if (dateNaissance === null)
{
console.log("Aucune date sélectionnée");
}
else
{
// Date du jour.
const aujourdHui = new Date();
// Créer une "date limite" correspondant à "aujourd'hui moins 18 ans".
// new Date(aujourdHui) crée une copie de la date du jour,
// pour éviter de modifier la variable aujourdHui.
const dateLimite = new Date(aujourdHui);
// getFullYear() renvoie l'année de la dateLimite, par exemple 2026.
// setFullYear(...) remplace uniquement l'année en conservant le mois et le jour.
// Ici, on enlève 18 à l'année en cours (ex.: 2026 - 18 = 2008).
dateLimite.setFullYear(dateLimite.getFullYear() - 18);
// Si la date de naissance est plus ancienne ou égale à la date limite,
// alors la personne a au moins 18 ans.
const estMajeur = dateNaissance <= dateLimite;
console.log(estMajeur); // Affiche: true si la personne est majeure, false si elle est mineure.
}
Exercices
Le travail se fait dans app.js et dans les modules. Chaque exercice doit produire un résultat visible dans la page. La console peut servir de repère et de débogage.
Exo-manipuler-contenu-textuel-dom-serie-01
Structure
Créer un dossier nommé Exo-manipuler-contenu-textuel-dom-serie-01, puis y organiser les fichiers et dossiers en respectant l'arborescence suivante :
Exo-manipuler-contenu-textuel-dom-serie-01/
|-- index.html
|-- css/
| └── style.css
└── js/
|-- app.js
└── modules/
|-- exo01.js
|-- exo02.js
|-- exo03.js
|-- exo04.js
|-- exo05.js
└── exo06.js
Copier le gabarit HTML suivant dans index.html. Ce gabarit contient tous les éléments nécessaires pour l'ensemble des exercices :
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./css/style.css">
<title>JS: Manipuler le contenu textuel du DOM - Série 01</title>
</head>
<body>
<h1>JS: Manipuler le contenu textuel du DOM - Série 01</h1>
<!-- Exo 01 -->
<section>
<h2>01. textContent</h2>
<p>
Scénario : basculer l'état d'un contenu publié.
</p>
<p id="exo01-statut">Statut : Brouillon</p>
<button id="exo01-btn-toggle">Publier</button>
</section>
<!-- Exo 02 -->
<section>
<h2>02. innerText et texte visible</h2>
<p>
Scénario : générer un résumé tel qu'il est <b>visible</b> à l'écran, sans inclure une note interne masquée.
</p>
<div class="carte">
<p id="exo02-texte">
Bonjour <b>Client</b>,
<br>
Votre demande a été prise en charge.
<span class="texte-cache">NOTE INTERNE: Ne pas afficher au client.</span>
</p>
<button id="exo02-btn-toggle">Générer le résumé visible</button>
<h3>Sortie</h3>
<pre id="exo02-sortie" class="zone-sortie">(vide)</pre>
</div>
</section>
<!-- Exo 03 -->
<section>
<h2>03. innerHTML et gabarit fiable</h2>
<p>
Scénario : afficher une bannière d'information depuis un gabarit connu et maîtrisé.
</p>
<div id="exo03-zone" class="zone-message">
(Aucun message pour le moment)
</div>
<button id="exo03-btn-toggle">Afficher le message</button>
</section>
<!-- Exo 04 -->
<section>
<h2>04. innerHTML et perte des événements</h2>
<p>
Scénario : rafraîchir une carte via <span class="commande" role="text">innerHTML</span> et observer la perte d'interactivité.
</p>
<div id="exo04-carte" class="carte">
<p><b>Produit</b>: Clavier mécanique</p>
<p>Disponibilité : <span id="exo04-etat">En stock</span></p>
<p>Dernière mise à jour : <span id="exo04-maj">Aucune</span></p>
<button id="exo04-btn-switch">Basculer disponibilité</button>
</div>
<hr>
<button id="exo04-btn-refresh">Rafraîchir la carte (innerHTML)</button>
<button id="exo04-btn-reset">Réinitialiser</button>
</section>
<!-- Exo 05 -->
<section>
<h2>05. Bonne pratique, modifier uniquement les textes</h2>
<p>
Scénario : rafraîchir les informations sans reconstruire tout le conteneur, afin de conserver les événements.
</p>
<div id="exo05-carte" class="carte">
<p><b>Produit</b>: Clavier mécanique</p>
<p>Disponibilité : <span id="exo05-etat">En stock</span></p>
<p>Dernière mise à jour : <span id="exo05-maj">Aucune</span></p>
<button id="exo05-btn-switch">Basculer disponibilité</button>
</div>
<hr>
<button id="exo05-btn-refresh">Rafraîchir les textes de la carte (textContent)</button>
</section>
<!-- Exo 06 -->
<section>
<h2>06. innerHTML vs textContent et simulation XSS</h2>
<p>
Scénario : afficher une note "utilisateur" dans une zone.
Comparer l'affichage avec <span class="commande" role="text">textContent</span> puis avec <span class="commande" role="text">innerHTML</span>.
</p>
<div id="exo06-zone" class="zone-message">
(Aucune note pour le moment)
</div>
<button id="exo06-btn-textcontent">Afficher avec textContent (sûr)</button>
<button id="exo06-btn-innerhtml">Afficher avec innerHTML (dangereux)</button>
<button id="exo06-btn-reset">Réinitialiser</button>
</section>
<script src="./js/app.js" type="module"></script>
</body>
</html>
Copier la feuille de style suivante dans style.css :
body {
font-family: sans-serif;
padding: 20px;
line-height: 1.5;
}
section {
border: 1px solid #ccc;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
}
h2 {
margin-top: 0;
}
button {
padding: 10px 15px;
cursor: pointer;
margin-right: 8px;
margin-top: 8px;
}
hr {
margin: 18px 0;
}
.carte {
border: 1px dashed #999;
padding: 14px;
border-radius: 8px;
background: #f7f7f7;
}
.zone-message {
border: 1px solid #999;
padding: 14px;
border-radius: 8px;
background: #fff;
margin-top: 10px;
}
.zone-sortie {
border: 1px solid #999;
padding: 12px;
border-radius: 8px;
background: #fff;
white-space: pre-wrap;
min-height: 44px;
}
.texte-cache {
display: none;
}
Ouvrir la page via un serveur local, car les modules l'exigent. Ouvrir ensuite les outils de développement du navigateur.
Exo 01
Objectif : Lire une valeur textuelle avec textContent puis basculer l'état au clic, en mettant aussi à jour le texte du bouton.
- Se rendre dans le fichier js/modules/exo01.js.
- Créer une fonction exportée (export nommé) appelée execExo01.
- Dans app.js, importer execExo01 depuis ./modules/exo01.js, puis appeler execExo01().
-
À l'intérieur de execExo01 :
- Afficher ----- Exo 01 ----- dans la console.
- Sélectionner #exo01-statut dans statutElem.
- Sélectionner #exo01-btn-toggle dans boutonToggleElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Stocker le texte d'origine de statutElem dans une constante texteOrigine.
- Définir le texte de l'état publié dans une constante texteMaj avec la valeur exacte "Statut : Publié".
- Créer une variable d'état let estPublie = false;.
-
Ajouter un écouteur "click" sur boutonToggleElem pour basculer l'état :
- Si estPublie vaut true, afficher texteMaj, sinon afficher texteOrigine.
- Mettre à jour le texte du bouton avec les valeurs exactes "Revenir en brouillon" et "Publier".
- Tester en cliquant plusieurs fois, vérifier l'alternance entre les deux états.
Exo 02
Objectif : Utiliser innerText pour récupérer un texte tel qu'il est visible à l'écran, puis l'afficher dans une zone de sortie.
- Se rendre dans le fichier js/modules/exo02.js.
- Créer et exporter une fonction fléchée nommée execExo02.
- Dans app.js, importer execExo02 depuis ./modules/exo02.js, puis appeler execExo02().
-
À l'intérieur de execExo02 :
- Afficher ----- Exo 02 ----- dans la console.
- Sélectionner #exo02-texte dans texteElem.
- Sélectionner #exo02-sortie dans sortieElem.
- Sélectionner #exo02-btn-toggle dans boutonToggleElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Définir une constante texteVide avec la valeur exacte "(vide)".
- Déclarer une variable d'état let sortieEstVisible = false;.
-
Ajouter un écouteur "click" sur boutonToggleElem :
- Si sortieEstVisible passe à true, écrire dans sortieElem.textContent la valeur de texteElem.innerText.
- Dans ce cas, remplacer le texte du bouton par la valeur exacte "Effacer le résumé".
- Si sortieEstVisible passe à false, remettre sortieElem.textContent à texteVide.
- Dans ce cas, remplacer le texte du bouton par la valeur exacte "Générer le résumé visible".
- Vérifier que la mention masquée NOTE INTERNE... ne se retrouve pas dans la sortie.
Exo 03
Objectif : Insérer un bloc HTML via innerHTML à partir d'un gabarit maîtrisé. Expliquer pourquoi cette source est considérée comme sûre.
- Se rendre dans le fichier js/modules/exo03.js.
- Créer et exporter une fonction fléchée nommée execExo03.
- Dans app.js, importer execExo03 depuis ./modules/exo03.js, puis appeler execExo03().
-
À l'intérieur de execExo03 :
- Afficher ----- Exo 03 ----- dans la console.
- Sélectionner #exo03-zone dans zoneElem.
- Sélectionner #exo03-btn-toggle dans boutonToggleElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Définir une constante texteRetour avec la valeur exacte "(Aucun message pour le moment)".
-
Définir une constante gabaritHtml en dur, avec le contenu exact suivant :
<p><b>Info</b> : maintenance prévue.</p> <ul> <li>Début : 22h00.</li> <li>Durée estimée : 30 minutes.</li> <li>Impact : accès intermittent.</li> </ul> - Déclarer une variable d'état let messageEstAffiche = false;.
-
Ajouter un écouteur "click" sur boutonToggleElem pour basculer :
- Si messageEstAffiche passe à true, injecter gabaritHtml via zoneElem.innerHTML et remplacer le texte du bouton par "Masquer le message".
- Si messageEstAffiche passe à false, remettre zoneElem.textContent à texteRetour et remplacer le texte du bouton par "Afficher le message".
- Ajouter un commentaire dans le code expliquant le point suivant l'utilisation de innerHTML reste acceptable ici uniquement parce que le gabarit est écrit en dur et contrôlé par le développeur, sans saisie utilisateur.
- Tester le switch et vérifier que le bloc s'affiche comme du HTML.
Exo 04
Objectif : Mettre à jour une carte via innerHTML et observer la perte d'interactivité. Le bouton "Basculer" doit modifier l'état et la date, puis cesser de fonctionner après un rafraîchissement du conteneur.
- Se rendre dans le fichier js/modules/exo04.js.
- Créer et exporter une fonction fléchée nommée execExo04.
- Dans app.js, importer execExo04 depuis ./modules/exo04.js, puis appeler execExo04().
-
À l'intérieur de execExo04 :
- Afficher ----- Exo 04 ----- dans la console.
-
Sélectionner les éléments suivants et stocker chaque référence dans une constante :
- #exo04-carte dans carteElem
- #exo04-etat dans etatElem
- #exo04-maj dans majElem
- #exo04-btn-switch dans boutonSwitchElem
- #exo04-btn-refresh dans boutonRefreshElem
- #exo04-btn-reset dans boutonResetElem
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Stocker carteElem.innerHTML dans une constante carteHtmlOrigine.
- Considérer les valeurs textuelles attendues suivantes pour l'état :
- État disponible : "En stock"
- État indisponible : "Rupture"
- État initial de la date : "Aucune"
-
Ajouter un écouteur click sur boutonSwitchElem.
Lors du clic :
- Basculer etatElem.textContent entre "En stock" et "Rupture".
- Mettre à jour majElem.textContent avec la date du moment.
-
Ajouter un écouteur click sur boutonRefreshElem.
Lors du clic :
- Reconstruire tout le contenu de carteElem via innerHTML.
- Conserver les libellés visibles suivants dans le HTML reconstruit :
- Produit avec la valeur "Clavier mécanique"
- Disponibilité avec l'état courant
- Dernière mise à jour avec la date du moment
- Le bouton avec le texte exact "Basculer disponibilité"
- Ne pas reposer l'écouteur du bouton switch après ce innerHTML.
-
Ajouter un écouteur click sur boutonResetElem.
Lors du clic :
- Remettre carteElem.innerHTML à carteHtmlOrigine.
- Resélectionner le nouveau bouton #exo04-btn-switch (celui recréé par le reset).
- Reposer l'écouteur du switch sur ce nouveau bouton.
- Forcer le texte de la date à la valeur exacte "Aucune".
-
Test
- Cliquer sur Basculer disponibilité, vérifier que l'état change et que la date se met à jour.
- Cliquer sur Rafraîchir la carte (innerHTML).
- Cliquer à nouveau sur Basculer disponibilité, vérifier que rien ne se passe.
- Cliquer sur Réinitialiser, puis retester le switch, vérifier que l'interactivité revient.
Exo 05
Objectif : Conserver les événements en évitant de reconstruire tout un conteneur. Modifier uniquement les textes nécessaires via textContent, sur au moins deux zones. Le bouton "Basculer" doit continuer à fonctionner après plusieurs rafraîchissements.
- Se rendre dans le fichier js/modules/exo05.js.
- Créer et exporter une fonction fléchée nommée execExo05.
- Dans app.js, importer execExo05 depuis ./modules/exo05.js, puis appeler execExo05().
-
À l'intérieur de execExo05 :
- Afficher ----- Exo 05 ----- dans la console.
-
Sélectionner les éléments suivants et stocker chaque référence dans une constante :
- #exo05-etat dans etatElem
- #exo05-maj dans majElem
- #exo05-btn-switch dans boutonSwitchElem
- #exo05-btn-refresh dans boutonRefreshElem
- #exo05-carte dans carteElem
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Considérer les valeurs textuelles attendues suivantes pour l'état et la date :
- État disponible : "En stock"
- État indisponible : "Rupture"
-
Ajouter un écouteur click sur boutonSwitchElem.
Lors du clic :
- Basculer etatElem.textContent entre "En stock" et "Rupture".
- Mettre à jour majElem.textContent avec la date du moment.
- Stocker le texte initial du bouton boutonRefreshElem dans une constante texteRefreshOrigine. La valeur attendue au chargement est "Rafraîchir les textes (textContent)".
-
Ajouter un écouteur click sur boutonRefreshElem.
Lors du clic :
- Mettre à jour majElem.textContent avec la date du moment.
- Remplacer le texte du bouton par le format suivant : texteRefreshOrigine + " (fait à " + [heure] + ")".
- Ne pas utiliser innerHTML sur carteElem. Les éléments doivent rester les mêmes afin de conserver les écouteurs.
-
Test
- Cliquer sur Basculer disponibilité, vérifier que l'état change et que la date se met à jour.
- Cliquer sur Rafraîchir les textes (textContent) plusieurs fois, vérifier que son libellé change avec l'heure.
- Cliquer à nouveau sur Basculer disponibilité, vérifier que l'interactivité est toujours présente.
Exo 06
Objectif : Illustrer un risque XSS en comparant textContent et innerHTML sur une même donnée. L'exemple déclenche une simple alerte, mais le principe peut mener à bien plus grave.
- Se rendre dans le fichier js/modules/exo06.js.
- Créer et exporter une fonction fléchée nommée execExo06.
- Dans app.js, importer execExo06 depuis ./modules/exo06.js, puis appeler execExo06().
-
À l'intérieur de execExo06 :
- Afficher ----- Exo 06 ----- dans la console.
- Sélectionner #exo06-zone dans zoneElem.
- Sélectionner les trois boutons #exo06-btn-textcontent, #exo06-btn-innerhtml et #exo06-btn-reset.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
-
Définir la constante suivante, à l'identique :
const noteUtilisateur = `<img src="x" onerror="alert('Attaque XSS')">`; - Définir une constante texteRetour avec la valeur exacte "(Aucune note pour le moment)".
-
Ajouter un écouteur sur le bouton dont le texte est "Afficher avec textContent" :
- Écrire noteUtilisateur dans zoneElem.textContent.
-
Ajouter un écouteur sur le bouton dont le texte est "Afficher avec innerHTML" :
- Écrire noteUtilisateur dans zoneElem.innerHTML.
- Observer qu'une alerte peut apparaître.
- Ajouter un écouteur sur #exo06-btn-reset pour remettre zoneElem.textContent à texteRetour.
- Ajouter un commentaire dans le code rappelant le point suivant textContent affiche du texte et neutralise les balises, alors que innerHTML interprète du HTML.
-
Observation dans le DOM
- Ouvrir l'onglet Elements.
- Sélectionner l'élément #exo06-zone.
- Comparer le contenu après un affichage via textContent puis via innerHTML.
Exo-manipuler-valeur-champ-formulaire-dom-serie-02
Structure
Créer un dossier nommé Exo-manipuler-valeur-champ-formulaire-dom-serie-02, puis y organiser les fichiers et dossiers en respectant l'arborescence suivante :
Exo-manipuler-valeur-champ-formulaire-dom-serie-02/
|-- index.html
|-- css/
| └── style.css
└── js/
|-- app.js
└── modules/
|-- exo07.js
|-- exo08.js
|-- exo09.js
|-- exo10.js
|-- exo11.js
|-- exo12.js
|-- exo13.js
|-- exo14.js
└── exo15.js
Copier le gabarit HTML suivant dans index.html. Ce gabarit contient tous les éléments nécessaires pour l'ensemble des exercices :
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./css/style.css">
<title>JS: Manipuler la valeur d'un champ de formulaire - Série 02</title>
</head>
<body>
<h1>JS: Manipuler la valeur d'un champ de formulaire - Série 02</h1>
<!-- Exo 07 -->
<section>
<h2>07. input text en temps réel, nettoyage et affichage</h2>
<p>
Scénario : saisir un nom dans un champ et afficher en direct la version nettoyée.
</p>
<label for="exo07-nom">Nom :</label>
<input type="text" id="exo07-nom" placeholder="Ex.: Martin ">
<p id="exo07-sortie" class="zone-sortie">Nom affiché : (vide)</p>
</section>
<!-- Exo 08 -->
<section>
<h2>08. input text, value et defaultValue</h2>
<p>
Scénario : comparer la valeur courante (JavaScript) et la valeur par défaut (HTML) d'un champ.
</p>
<label for="exo08-prenom">Prénom :</label>
<input type="text" id="exo08-prenom" value="Alice">
<div class="zone-actions">
<button id="exo08-btn-afficher">Afficher value et defaultValue</button>
<button id="exo08-btn-reset">Réinitialiser l'affichage</button>
</div>
<p id="exo08-value" class="zone-sortie">value : (vide)</p>
<p id="exo08-defaultvalue" class="zone-sortie">defaultValue : (vide)</p>
</section>
<!-- Exo 09 -->
<section>
<h2>09. textarea, value et defaultValue</h2>
<p>
Scénario : reproduire la comparaison value vs defaultValue sur un textarea.
</p>
<label for="exo09-message">Message :</label>
<textarea id="exo09-message" rows="4">Message initial écrit dans le HTML.</textarea>
<div class="zone-actions">
<button id="exo09-btn-afficher">Afficher value et defaultValue</button>
<button id="exo09-btn-reset">Réinitialiser l'affichage</button>
</div>
<p id="exo09-value" class="zone-sortie">value : (vide)</p>
<p id="exo09-defaultvalue" class="zone-sortie">defaultValue : (vide)</p>
</section>
<!-- Exo 10 -->
<section>
<h2>10. select, valeur sélectionnée et valeur inexistante</h2>
<p>
Scénario : afficher la valeur sélectionnée et tester l'affectation d'une valeur qui n'existe pas.
</p>
<label for="exo10-pays">Pays :</label>
<select id="exo10-pays">
<option value="be">Belgique</option>
<option value="fr">France</option>
<option value="nl">Pays-Bas</option>
</select>
<div class="zone-actions">
<button id="exo10-btn-inexistant">Forcer une valeur inexistante</button>
<button id="exo10-btn-reset">Réinitialiser</button>
</div>
<p id="exo10-sortie" class="zone-sortie">Sélection : (vide)</p>
</section>
<!-- Exo 11 -->
<section>
<h2>11. checkbox, checked et defaultChecked</h2>
<p>
Scénario : activer ou désactiver une préférence, puis comparer l'état courant et l'état par défaut.
</p>
<label class="ligne">
<input type="checkbox" id="exo11-newsletter">
Recevoir la newsletter
</label>
<div class="zone-actions">
<button id="exo11-btn-console">Afficher checked et defaultChecked (console)</button>
<button id="exo11-btn-reset">Réinitialiser le message</button>
</div>
<p id="exo11-sortie" class="zone-sortie">Préférence : (non définie)</p>
</section>
<!-- Exo 12 -->
<section>
<h2>12. radios, valeur sélectionnée et sélection forcée</h2>
<p>
Scénario : choisir un niveau, afficher la valeur en direct, puis forcer une sélection via JavaScript.
</p>
<div class="groupe">
<label class="ligne">
<input type="radio" name="exo12-niveau" value="debutant">
Débutant
</label>
<label class="ligne">
<input type="radio" name="exo12-niveau" value="intermediaire">
Intermédiaire
</label>
<label class="ligne">
<input type="radio" name="exo12-niveau" value="avance">
Avancé
</label>
</div>
<div class="zone-actions">
<button id="exo12-btn-existant">Forcer la valeur "intermediaire"</button>
<button id="exo12-btn-inexistant">Tenter de forcer une valeur inexistante</button>
<button id="exo12-btn-reset">Réinitialiser</button>
</div>
<p id="exo12-sortie" class="zone-sortie">Niveau sélectionné : (aucun)</p>
</section>
<!-- Exo 13 -->
<section>
<h2>13. input number, lecture via value et traitement des cas vides</h2>
<p>
Scénario : saisir une quantité, afficher la valeur, puis gérer proprement le cas où rien n'est saisi.
</p>
<label for="exo13-quantite">Quantité (required) :</label>
<input type="number" id="exo13-quantite" required placeholder="Ex.: 3">
<p id="exo13-sortie" class="zone-sortie">Quantité affichée : (vide)</p>
</section>
<!-- Exo 14 -->
<section>
<h2>14. input number, lecture via valueAsNumber</h2>
<p>
Scénario : refaire l'exo précédent avec <span class="commande" role="text">valueAsNumber</span> pour simplifier le traitement.
</p>
<label for="exo14-quantite">Quantité (required) :</label>
<input type="number" id="exo14-quantite" required placeholder="Ex.: 3">
<p id="exo14-sortie" class="zone-sortie">Quantité affichée : (vide)</p>
</section>
<!-- Exo 15 -->
<section>
<h2>15. input date, planifier une échéance</h2>
<p>
Scénario : choisir une date d'échéance, afficher un résumé utile pour un écran "planning".
</p>
<label for="exo15-echeance">Échéance :</label>
<input type="date" id="exo15-echeance">
<div class="zone-actions">
<button id="exo15-btn-aujourdhui">Définir aujourd'hui</button>
<button id="exo15-btn-reset">Réinitialiser</button>
</div>
<p id="exo15-sortie" class="zone-sortie">Échéance : (aucune)</p>
</section>
<script src="./js/app.js" type="module"></script>
</body>
</html>
Copier la feuille de style suivante dans style.css :
body {
font-family: sans-serif;
padding: 20px;
line-height: 1.5;
}
section {
border: 1px solid #ccc;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
}
h2 {
margin-top: 0;
}
label {
display: inline-block;
margin-right: 10px;
}
input, select, textarea {
padding: 8px 10px;
margin-top: 8px;
min-width: 260px;
}
textarea {
min-width: 320px;
}
button {
padding: 10px 15px;
cursor: pointer;
margin-right: 8px;
margin-top: 10px;
}
.zone-actions {
margin-top: 6px;
}
.zone-sortie {
border: 1px solid #999;
padding: 12px;
border-radius: 8px;
background: #fff;
margin-top: 12px;
}
.ligne {
display: block;
margin-top: 8px;
}
.groupe {
margin-top: 8px;
}
Ouvrir la page via un serveur local, car les modules l'exigent. Ouvrir ensuite les outils de développement du navigateur.
Exo 07
Objectif : Récupérer en temps réel la saisie d'un input text, afficher la version nettoyée dans la page, et afficher la version brute dans la console.
- Se rendre dans le fichier js/modules/exo07.js.
- Créer et exporter une fonction fléchée nommée execExo07.
- Dans app.js, importer execExo07 depuis ./modules/exo07.js, puis appeler execExo07().
-
À l'intérieur de execExo07 :
- Afficher ----- Exo 07 ----- dans la console.
- Sélectionner #exo07-nom dans champNomElem.
- Sélectionner #exo07-sortie dans sortieElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Ajouter un écouteur sur l'événement "input" pour réagir à chaque modification de saisie.
-
Dans le gestionnaire :
- Récupérer la valeur brute via champNomElem.value dans valeurBrute.
- Afficher la version brute dans la console en rendant les espaces visibles, via JSON.stringify.
- Créer une version nettoyée dans valeurNettoyee avec trim().
- Si valeurNettoyee vaut une chaîne vide, utiliser la valeur exacte "(vide)".
- Afficher dans la page via sortieElem.textContent en respectant le format exact "Nom affiché : " + [valeur].
-
Utiliser la forme suivante pour mettre en évidence les espaces en console
console.log(JSON.stringify(valeurBrute));
- Tester en tapant " Martin ", vérifier la différence entre console et page.
Exo 08
Objectif : Comparer value et defaultValue sur un input possédant un attribut HTML value.
- Se rendre dans le fichier js/modules/exo08.js.
- Créer et exporter une fonction fléchée nommée execExo08.
- Dans app.js, importer execExo08 depuis ./modules/exo08.js, puis appeler execExo08().
-
À l'intérieur de execExo08 :
- Afficher ----- Exo 08 ----- dans la console.
- Sélectionner #exo08-prenom dans champElem.
- Sélectionner #exo08-btn-afficher dans boutonAfficherElem.
- Sélectionner #exo08-btn-reset dans boutonResetElem.
- Sélectionner #exo08-value dans valueElem.
- Sélectionner #exo08-defaultvalue dans defaultValueElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Définir une constante texteVide avec la valeur exacte "(vide)".
-
Sur clic de boutonAfficherElem :
- Écrire dans valueElem.textContent le texte au format exact "value : " + champElem.value.
- Écrire dans defaultValueElem.textContent le texte au format exact "defaultValue : " + champElem.defaultValue.
-
Sur clic de boutonResetElem :
- Remettre valueElem.textContent à la valeur exacte "value : (vide)".
- Remettre defaultValueElem.textContent à la valeur exacte "defaultValue : (vide)".
-
Test
- Cliquer sur Afficher, vérifier l'égalité entre value et defaultValue.
- Modifier la saisie dans le champ, puis recliquer sur Afficher, constater que defaultValue ne bouge pas.
- Ouvrir l'inspecteur, modifier l'attribut HTML value de l'input, puis recliquer sur Afficher.
- Observer la mise à jour de defaultValue.
Exo 09
Objectif : Reproduire l'exo 08 avec un textarea et distinguer texte HTML initial et valeur courante.
- Se rendre dans le fichier js/modules/exo09.js.
- Créer et exporter une fonction fléchée nommée execExo09.
- Dans app.js, importer execExo09 depuis ./modules/exo09.js, puis appeler execExo09().
-
À l'intérieur de execExo09 :
- Afficher ----- Exo 09 ----- dans la console.
- Sélectionner #exo09-message dans champElem.
- Sélectionner #exo09-btn-afficher dans boutonAfficherElem.
- Sélectionner #exo09-btn-reset dans boutonResetElem.
- Sélectionner #exo09-value dans valueElem.
- Sélectionner #exo09-defaultvalue dans defaultValueElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Définir une constante texteVide avec la valeur exacte "(vide)".
-
Sur clic de boutonAfficherElem :
- Écrire dans valueElem.textContent le texte au format exact "value : " + champElem.value.
- Écrire dans defaultValueElem.textContent le texte au format exact "defaultValue : " + champElem.defaultValue.
-
Sur clic de boutonResetElem :
- Remettre valueElem.textContent à la valeur exacte "value : (vide)".
- Remettre defaultValueElem.textContent à la valeur exacte "defaultValue : (vide)".
-
Test
- Cliquer sur Afficher, observer les deux valeurs.
- Modifier le texte dans le textarea comme un utilisateur, puis recliquer sur Afficher.
- Ouvrir l'inspecteur et modifier le texte initial écrit entre les balises <textarea>...</textarea>, puis recliquer sur Afficher.
- Observer la mise à jour de defaultValue.
Exo 10
Objectif : Récupérer la valeur sélectionnée d'un select et observer le comportement lors d'une affectation d'une valeur inexistante.
- Se rendre dans le fichier js/modules/exo10.js.
- Créer et exporter une fonction fléchée nommée execExo10.
- Dans app.js, importer execExo10 depuis ./modules/exo10.js, puis appeler execExo10().
-
À l'intérieur de execExo10 :
- Afficher ----- Exo 10 ----- dans la console.
- Sélectionner #exo10-pays dans selectElem.
- Sélectionner #exo10-sortie dans sortieElem.
- Sélectionner #exo10-btn-inexistant dans boutonInexistantElem.
- Sélectionner #exo10-btn-reset dans boutonResetElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
-
Créer une fonction mettreAJourSortie qui écrit dans sortieElem.textContent :
- Si aucune option n'est sélectionnée, écrire la valeur exacte "Sélection : (aucune option sélectionnée)".
- Sinon, écrire au format exact "Sélection : " + selectElem.value + " (" + selectElem.selectedOptions[0].text + ")".
- Ajouter un écouteur "change" sur selectElem qui appelle mettreAJourSortie().
-
Sur clic de boutonInexistantElem :
- Assigner une valeur inexistante, par exemple selectElem.value = "xx".
- Appeler mettreAJourSortie() pour afficher l'état obtenu.
-
Sur clic de boutonResetElem :
- Remettre le select sur une valeur existante, par exemple selectElem.value = "be".
- Appeler mettreAJourSortie().
- Appeler mettreAJourSortie() une première fois à la fin, pour initialiser l'affichage.
Exo 11
Objectif : Utiliser checked et defaultChecked sur une checkbox, puis tester l'effet d'une modification de l'attribut HTML checked dans l'inspecteur.
- Se rendre dans le fichier js/modules/exo11.js.
- Créer et exporter une fonction fléchée nommée execExo11.
- Dans app.js, importer execExo11 depuis ./modules/exo11.js, puis appeler execExo11().
-
À l'intérieur de execExo11 :
- Afficher ----- Exo 11 ----- dans la console.
- Sélectionner #exo11-newsletter dans caseElem.
- Sélectionner #exo11-sortie dans sortieElem.
- Sélectionner #exo11-btn-console dans boutonConsoleElem.
- Sélectionner #exo11-btn-reset dans boutonResetElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Stocker le texte d'origine de sortieElem dans texteOrigine.
-
Ajouter un écouteur "change" sur caseElem :
- Écrire "Préférence : Activée" si caseElem.checked vaut true.
- Écrire "Préférence : Désactivée" sinon.
-
Sur clic de boutonConsoleElem, afficher au minimum :
- caseElem.checked
- caseElem.defaultChecked
- Sur clic de boutonResetElem, remettre uniquement sortieElem.textContent à texteOrigine.
-
Test
- Cliquer sur le bouton console au chargement, noter les deux valeurs.
- Ouvrir l'inspecteur, ajouter l'attribut HTML checked sur l'input, puis recliquer sur le bouton console.
- Cocher ou décocher manuellement la checkbox, puis modifier à nouveau l'attribut HTML, puis recliquer sur le bouton console.
- Observer la différence entre état courant et état par défaut.
Exo 12
Objectif : Afficher en direct la valeur d'un groupe de radios, puis forcer une sélection existante, et enfin gérer proprement le cas d'une valeur inexistante.
- Se rendre dans le fichier js/modules/exo12.js.
- Créer et exporter une fonction fléchée nommée execExo12.
- Dans app.js, importer execExo12 depuis ./modules/exo12.js, puis appeler execExo12().
-
À l'intérieur de execExo12 :
- Afficher ----- Exo 12 ----- dans la console.
- Sélectionner tous les radios du groupe via querySelectorAll et stocker dans radiosElements.
- Sélectionner #exo12-sortie dans sortieElem.
- Sélectionner #exo12-btn-existant, #exo12-btn-inexistant et #exo12-btn-reset.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Stocker le texte d'origine de sortieElem dans texteOrigine.
-
Créer une fonction mettreAJourSortie :
- Récupérer le radio coché via document.querySelector('input[name="exo12-niveau"]:checked').
- Si aucun radio n'est coché, afficher la valeur exacte "Niveau sélectionné : (aucun)".
- Sinon, afficher au format exact "Niveau sélectionné : " + radioCoche.value.
- Pour chaque radio, ajouter un écouteur "change" qui appelle mettreAJourSortie().
-
Sur clic du bouton Forcer la valeur "intermediaire" :
- Sélectionner le radio attendu via document.querySelector('input[name="exo12-niveau"][value="intermediaire"]').
- Si l'élément vaut null, afficher la valeur exacte "Niveau sélectionné : (valeur introuvable)" et arrêter le traitement.
- Sinon, cocher le radio via checked = true, puis appeler mettreAJourSortie().
-
Sur clic du bouton valeur inexistante :
- Tenter de sélectionner document.querySelector('input[name="exo12-niveau"][value="inexistant"]').
- Si le résultat vaut null, afficher la valeur exacte "Niveau sélectionné : (valeur introuvable)".
-
Sur clic du bouton Réinitialiser :
- Décocher tout le groupe en passant chaque radioElem.checked à false.
- Remettre sortieElem.textContent à texteOrigine.
- Appeler mettreAJourSortie() une première fois à la fin.
Exo 13
Objectif : Lire un input type="number" via value et gérer le cas vide correctement, sans transformer une chaîne vide en zéro par erreur.
- Se rendre dans le fichier js/modules/exo13.js.
- Créer et exporter une fonction fléchée nommée execExo13.
- Dans app.js, importer execExo13 depuis ./modules/exo13.js, puis appeler execExo13().
-
À l'intérieur de execExo13 :
- Afficher ----- Exo 13 ----- dans la console.
- Sélectionner #exo13-quantite dans champElem.
- Sélectionner #exo13-sortie dans sortieElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Afficher une observation en console une seule fois, par exemple Number(''), pour constater le faux zéro.
- Ajouter un écouteur "input" sur champElem.
-
Dans le gestionnaire :
- Récupérer la chaîne via champElem.value dans valeurTexte.
- Si valeurTexte.trim() vaut une chaîne vide, afficher la valeur exacte "Quantité affichée : (aucune valeur)".
- Sinon, convertir via Number(valeurTexte) dans valeurNombre.
- Si Number.isNaN(valeurNombre), afficher la valeur exacte "Quantité affichée : (valeur invalide)".
- Sinon, afficher au format exact "Quantité affichée : " + valeurNombre.
Exo 14
Objectif : Refaire l'exo 13 avec valueAsNumber et comparer la simplification du traitement.
- Se rendre dans le fichier js/modules/exo14.js.
- Créer et exporter une fonction fléchée nommée execExo14.
- Dans app.js, importer execExo14 depuis ./modules/exo14.js, puis appeler execExo14().
-
À l'intérieur de execExo14 :
- Afficher ----- Exo 14 ----- dans la console.
- Sélectionner #exo14-quantite dans champElem et #exo14-sortie dans sortieElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Ajouter un écouteur "input" sur champElem.
-
Dans le gestionnaire :
- Récupérer la valeur via champElem.valueAsNumber dans valeurNombre.
- Si Number.isNaN(valeurNombre), afficher la valeur exacte "Quantité affichée : (aucune valeur)".
- Sinon, afficher au format exact "Quantité affichée : " + valeurNombre.
Exo 15
Objectif : Exploiter un input type="date" pour afficher un résumé exploitable, avec une notion de délai.
- Se rendre dans le fichier js/modules/exo15.js.
- Créer et exporter une fonction fléchée nommée execExo15.
- Dans app.js, importer execExo15 depuis ./modules/exo15.js, puis appeler execExo15().
-
À l'intérieur de execExo15 :
- Afficher ----- Exo 15 ----- dans la console.
- Sélectionner #exo15-echeance dans champDateElem.
- Sélectionner #exo15-sortie dans sortieElem.
- Sélectionner #exo15-btn-aujourdhui dans boutonAujourdhuiElem.
- Sélectionner #exo15-btn-reset dans boutonResetElem.
- Vérifier les sélections. Si un élément manque, afficher un message clair, puis quitter la fonction avec return.
- Stocker le texte d'origine de sortieElem dans texteOrigine.
-
Créer une fonction mettreAJourSortie qui :
- Si champDateElem.value est vide, remet sortieElem.textContent à texteOrigine.
- Sinon, calcule le nombre de jours entre aujourd'hui et la date choisie, puis affiche un message au format suivant :
- Date invalide, afficher la valeur exacte "Échéance : (date invalide)".
- Date passée, afficher "Échéance : YYYY-MM-DD (dépassée de N jour(s))".
- Date du jour, afficher "Échéance : YYYY-MM-DD (aujourd'hui)".
- Date future, afficher "Échéance : YYYY-MM-DD (dans N jour(s))".
- Ajouter un écouteur "change" sur champDateElem qui appelle mettreAJourSortie().
-
Sur clic de boutonAujourdhuiElem :
- Construire la chaîne au format YYYY-MM-DD correspondant à aujourd'hui.
- Assigner cette valeur à champDateElem.value.
- Appeler mettreAJourSortie().
-
Sur clic de boutonResetElem :
- Vider champDateElem.value.
- Remettre sortieElem.textContent à texteOrigine.
- Appeler mettreAJourSortie() une première fois à la fin.
-
Test
- Sélectionner une date future, vérifier l'affichage du nombre de jours restants.
- Sélectionner une date passée, vérifier le message d'alerte.
- Utiliser le bouton aujourd'hui, vérifier que la date se remplit correctement.
- Utiliser Réinitialiser, vérifier le retour au texte d'origine.