JavaSript

Les selecteurs :

Les sélecteurs servent à manipuler le code "html" et "css" dans une page web, on va pouvoir récupérer, modifier, créer ou supprimer des éléments de notre page web.

Dans les sélecteurs, on parlera de "DOM" (Document Object Model), le "DOM" est une représentation du document HTML source, il s’agit pour l'essentiel d’une conversion de la structure et du contenu du document HTML en un modèle objet utilisable par divers programmes.

La structure d'objet du DOM est représentée par ce qu'on appelle une "arborescence de nœuds" (node tree), on l'appelle ainsi parce qu'il peut être considéré comme un arbre qui se ramifie en plusieurs branches enfants, chacune pouvant avoir des feuilles.
Le premier parent est l'élément racine <html>, les "branches" enfants sont les éléments imbriqués et les "feuilles" sont le contenu des éléments.

Chaque nœud de cet arbre DOM est un "objet HTML Element" (header, main, div…), pour le dire autrement, JavaScript a regroupé dans un même objet deux choses :
- les informations sur cet objet (son nom, son id, sa position, etc.) : ce sont les propriétés de l’objet;
- ce que cet objet est capable de faire (réagir au clic, par exemple) : ce sont les méthodes.

Le DOM est donc une interface vers un document HTML, il est utilisé par les navigateurs dans une première étape pour déterminer ce qui peut être rendu à l'écran, et par JavaScript pour modifier le contenu, la structure ou le style de la page.

En premier lieu, notre but est de récupérer les éléments de l’arbre DOM, qui a pour racine la balise <body> et pour cela javaScript doit ainsi construire une variable globale nommée "document" qui doit être accessible depuis n’importe où dans notre code.

Récupérer un élément dans le DOM :

Récupérer ou cibler un élément dans le DOM avec la méthode "getElementById" (obtenir l'élément par identifiant, traduit en français), cette méthode, et probablement la plus simple, comme son nom l’indique, elle permet de récupérer un élément en fournissant son id en paramètre.

Ici, j'ai mis "monId" dans la balise <p>, si vous mettez le curseur sur le résultat indiqué dans la console, il doit vous mettre en évidence ce paragraphe, voici un exemple de son fonctionnement :

 <p id="monId">texte</p> <!--on indique l'id dans la balise html --> 
let maVariableId = document.getElementById("monId"); 
console.log(maVariableId);

Ici, on a demandé à JavaScript, depuis "document" donc toute la page : Trouve-moi un élément HTML qui a pour id "monId”, puis on affiche le résultat de la variable "maVariableId" dans la console.

Pour les éléments n'ayant pas de "id", on peut récupérer ces éléments par leur sélecteur "css" avec la méthode "QuerySelector" (sélecteur de requête, traduit en français), querySelector nous permet de trouver le premier élément qui correspond au sélecteur CSS proposé, elle est la méthode moderne recommandée.

Exemple :

let baliseh3 = document.querySelector("h3");
console.log(baliseh3);

Ici, JavaScript nous a récupéré le premier élément "h3" qu'il a trouvé dans le document (le titre en haut de la page), il ne prendra pas en compte les autres "h3" dans le reste du code

QuerySelector fonctionne aussi avec les selecteurs "id", contrairement au "getElementById" le symbole # est obligatoire, la console affichera ce paragraphe.

let querySelectorId = document.querySelector("#querySelectorId"); 
// permet de selectionner une balise avec le nom d'un "id"
console.log(querySelectorId)

QuerySelector fonctionne aussi avec les sélecteurs de "class", comme en css, il faut mettre le point avant le nom de la class pour pouvoir les utiliser, la console affichera ce paragraphe.

let classS = document.querySelector(".classS"); 
// permet de selectionner une balise avec le nom de la "class"
console.log(classS)

Exemple d'une selection avec une balise <b> qui se trouve dans un paragraphe qui contient une class gras, vous pouvez tester dans la console cela affichera le mot en gras.

 <p class="gras">Selectionne le mot dans une balise <b>gras</b> qui contient la class gras</p> 
let gras = document.querySelector(".gras b");
console.log(gras);

Maintenant pour sélectionner, récupérer ou cibler plusieurs éléments du même type, on va utiliser la méthode "QuerySelectorAll" (Tout les Sélecteur de requête, traduit en français), ici, le principe est le même que pour QuerySelector, mais il sélectionnera toutes les balises "h3" qui sont dans le code.
Pour l'exemple, on va insérer une balise h3 avec le mot TEST, la console mettra en évidence toutes les balises h3 qu'elle rencontre dans le code de la page, c'est-à-dire le titre de la page en haut et le mot TEST que l'on vient d'insérer.

TEST

let balisesh3 = document.querySelectorAll("h3");
console.log(balisesh3);

Pour parcourir les différents h3 dans le code,on peut utiliser une boucle

for (let i = 0; i < balisesh3.length; i++) {
console.log(balisesh3[i]);
}

Modifier du texte dans le DOM :

Prenons comme exemple ce code en html, on va y mettre une class pour l'identifier plus facilement :

 <p class="amended">"texte non modifié"</p>

on selectione la class "amended" avec le querySelector :

let amended = document.querySelector(".amended");

Ensuite on modifie le texte avec la propriété "textContent" (Contenu du texte, en français), elle représente le contenu textuel d'un nœud et de ses descendants. :

amended.textContent= "Ce texte a été modifié";  

Et voici le résultat :

"texte non modifié"

* (Si on utilise une extension qui désactive le JavaScript, on pourra voir le texte d'origine.)

Cependant cette propriété ne permet de modifier que les éléments de textes, mais ne permet pas de modifier les éléments html, les balises ne seront pas interprétées.
Pour modifier le texte, avec les éléments HTML, on va devoir utiliser la méthode "innerHTML" (HTML interne, en français).

Pour comparer et comprendre la distinction entre ces deux propriétés, prenons deux exemples l'une avec la propriété "textContent" et l'autre avec la propriété "innerHTML", on va lui inclure une balise <mark> pour bien voir la différence.

 <p class="exemple1">test</p> 
let exemple1 = document.querySelector(".exemple1");
exemple1.textContent= "<mark>La balise n'est pas interpété</mark>";

Résultat :

test

 <p class="exemple2">test</p> 
let exemple2 = document.querySelector(".exemple2");
    exemple2.innerHTML= "<mark>La balise est interpété</mark>";

Résultat :

test

/!\ la balise <mark> est une balise de stylisation comme la balise <b>, <i>, <u> ou encore <s>

Modifier un attribut dans le DOM :

Pour modifier un élément du DOM, on commence par récupérer l'élément avec l'une des propriétés précédentes, ensuite on va utilise la propriété "setAttribute" (définir l'attribut, traduit en français), c'est l'une des propriétés la plus générique qui permet de définir n’importe quel attribut.

"setAttribute" ajoute un nouvel attribut ou change la valeur d'un attribut existant pour l'élément spécifié. Si l'attribut existe déjà, la valeur est mise à jour ; sinon, un nouvel attribut est ajouté avec le nom et la valeur spécifiés.

Pour cet exemple, partons du code html ci-dessous, on lui ajoute une balise <span> avec une class pour le différencier de l'autre exemple :

<span class="exemple3">
<img src="asset/img/image1.png" alt="image1"/>
<img src="asset/img/image1.png" alt="image1"/>
<img src="asset/img/image1.png" alt="image1"/>
<img src="asset/img/image1.png" alt="image1"/>
</span>

On récupère l'élément avec la balise <img > et la méthode "querySelector" que l'on insère dans une variable.

let baliseImage = document.querySelector(".exemple3 img");

Ensuite, on indique que c'est l'attribut src qu'il va falloir modifier, puis on indique le chemin de la nouvelle image.

baliseImage.setAttribute("src", "asset/img/image2.png");
                    
// Il existe une méthode raccourcie pour écrire la même chose
baliseImage.src = "asset/img/image2.png"; 
 
// on peut aussi l'écrire sans déclarer de variable
document.querySelector("img").setAttribute("src", "asset/img/image2.png");
image1 image1 image1 image1

Comme on peut le constater, seule la première image a été changée, car on a utilisé la méthode "querySelector".

Maintenant, si je veux changer les quatre images, on reprend le même exemple en changeant le nom de la class qui est dans le <span> :

<span class="exemple4">
<img src="asset/img/image1.png" alt="image1"/>
<img src="asset/img/image1.png" alt="image1"/>
<img src="asset/img/image1.png" alt="image1"/>
<img src="asset/img/image1.png" alt="image1"/>
</span>

Il va donc falloir qu'on utilise la méthode "querySelectorAll" avec une boucle, comme ceci :

let baliseImageBis = document.querySelectorAll(".exemple4 img");

for (let i=0; i < baliseImageBis.length; i++) {
baliseImageBis[i].setAttribute("src", "asset/img/image2.png");
}

Résultat :

image1 image1 image1 image1

Modifier les classes dans le DOM :

Pour supprimer ou ajouter une class dans un élément, on peut utiliser la propriété "classList" avec les méthodes "add" et "remove", on va partir d'une image d'origine.

<img src="asset/img/JavaScript.png" alt="javaScript">
javaScript

Maintenant, on va voir comment lui ajouter des class, ici, on va lui donner une class "img1" pour qu'on puisse sélectionner l'élément, ensuite on va lui rajouter deux autres class pour la stylisation "border" et "grayscale" via la propriété "classList" et la méthode "add".

Exemple :

<img class="img1" src="asset/img/JavaScript.png" alt="javaScript">
const img1 = document.querySelector('.img1');
img1.classList.add("border", "grayscale");
javaScript

Si on va verifier dans l'inspecteur, on pourra constater que les deux autres "class" on été rajouter.

Reprenons la même image d'origine en lui ajoutant une class de selection "img2" et les deux autres pour la stylisation et on va devoir supprimer la class "grayscale" via la propriété "classList" et la méthode "remove", exemple :

<img class="img2 border grayscale" src="asset/img/javaScript.png" alt="javaScript"></img>
const img2 = document.querySelector('.img2');
img2.classList.remove("grayscale");
javaScript

Si on va verifier dans l'inspecteur, on pourra constater que la class "grayscale" a été supprimer.

Autre cas de figure, on peut remplacer une class par une autre, ici, l'image comporte la class "img3" pour la selection et "border" pour la stylisation, on va remplacer la class "border" par la class "grayscale", voici un exemple :

<img class="img3 border" src="asset/img/javaScript.png" alt="javaScript"></img>
const img3 = document.querySelector('.img3');
img3.classList.replace("border", "grayscale");
javaScript

Si on va vérifier dans l'inspecteur, on pourra constater que la class "border" a été remplacé par la class "grayscale".

Créer un nouvel élémént :

Créez une nouvelle balise grâce à la méthode "createElement" (créer un élément, traduit en français) fournie par JavaScript et accessible depuis "document", elle permet de créer n’importe quelle balise.

On commence par créer un nouveau paragraphe :

let newElement = document.createElement("p");

Une fois l’élément créé, il n'apparaît pas encore dans la page, pour que cette nouvelle balise apparaisse, nous devons l’insérer dans l’arbre DOM afin que JavaScript sache exactement à quel endroit il faudra mettre l’élément.
Pour cela, nous devons, déterminer quel sera l’élément parent, il faudra utiliser la méthode "appendChild" (ajouter un enfant, traduit en français) pour l'insérer dans l'élément parent.

On va récupérer un élément parent existant :

let parentElement = document.querySelector(".testCreateElement");

Ajouter le nouvel élément au parent avec la méthode "appendChild" :

parentElement.appendChild("newElement");

On créer une balise "div" qui va servir de parent pour le nouveau paragraphe, avec la class "testCreateElement" pour la selection et un style border pour le différencier :

 <div class="testCreateElement border"></div> 

Le paragraphe sera vide, donc si on veut rajouter du texte dans le paragraphe :

newElement.append("Je suis le texte rajouté.");

Résultat :

Par défaut, j'ai mis un "margin-bottom" à 0px pour tous les paragraphes, du coup on va rajouter un effet de style avec les class "noReassembled" qui remet un "margin-bottom à 14px" et "withdrawal" qui ajoute un "margin-left à 20px" :

newElement.classList.add("noReassembled", "withdrawal")

Le problème est dès que le code de la page va devenir un peu long, il va être difficile de se repérer dans le code, comment savoir avec précision quels éléments sont les enfants de qui ?
Dans ce cas, la solution est d’écrire directement du HTML, sous forme de texte, et de l’insérer dans une propriété innerHTML.
Pour cela on peut utiliser "l’interpolation" (vu dans le chapitre sur les opérateurs) pour générer du HTML.

Exemple :

let contenuTitre = "Mon titre rajouté"
let contenuParagraphe = "Mon paragraphe rajouté"
let div = `<div>
<h3 class="withdrawal">${contenuTitre}</h3>
<p class="noReassembled withdrawal">${contenuParagraphe}</p>
</div>`;

Maintenant que le code HTML est généré, nous devons l’insérer dans un élément existant de la page, pour cela, on choisit la balise qui va contenir notre code HTML, et on met simplement ce code HTML dans la propriété innerHTML :

let main = document.querySelector(".aRajouter");
main.innerHTML = (div);

La "div" doit être intégrée dans une balise, on va donc créer une nouvelle balise "aside" avec une class "border" :

 <aside class="border"></aside> 

Résultat :

~~ Fin ~~