# Introduction au DOM

Le Modèle Objet de Document (DOM: Document object Model) est la représentation en objets de la structure, du style et du contenu d'un document web. L'API du DOM permet d'interagir avec le HTML et le CSS grâce à JavaScript.

# Le DOM : Document Object Model

Lors de la lecture du HTML par le navigateur, il convertit les noeuds (c'est-à-dire les balises, les commentaires, les textes...) en objets manipulables par JavaScript. Les éléments du DOM ne font pas partie du langage JavaScript, et ne sont donc pas standardisés par le TC39 mais par le W3C (opens new window).

Le DOM représente le document HTML sous forme d'arbre : Chaque branche est un nœud, et chaque nœud peut contenir un ou d'autres nœud(s).

Par exemple, à partir de ce code (très simple) :

<body>
    <header>
        <h1>
            Cours ESILV
        </h1>
    </header>
    <ul>
        <li>HTML</li>
        <li>CSS</li>
    </ul>
    <footer>Stanislas Ormières</footer>
</body>

Le navigateur générera un arbre ressemblant à ceci :

Representation DOM

Chacun de ces rectangles sur le schéma est un objet, avec un (très) grand nombre de propriétés. Ces propriétés permettent de connaître de façon programmatique leur contenu, les attributs de la balises, le nom de la balise et d'y attacher des événements (cf. plus loin). On peut aussi changer le contenu, les attributs et leurs valeurs, changer le type de balise (changer le "h1" par un "h2", ajouter une classe CSS...), on peut aussi supprimer du contenu et en ajouter.

Pour plus de détails, visiter l'introduction au DOM sur le MDN (opens new window)

# L'objet document

C'est le point d'entrée du DOM : il contient une représentation de tous les objets de la page (visibles ou non) et une (très) grande quantité de méthodes et propriétés utiles.

Quelques exemples de commandes que vous pouvez taper dans les dev-tools du navigateur :

console.dir(document)
console.dir(document.head)
console.dir(document.body)
console.dir(document.images)

Par exemple, pour console.dir(document.images) sur cette page, vous verrez quelque chose comme ceci :

HTMLCollection
​
0: <img class="logo" src="/assets/img/ninja@mini.png" alt="Cours développement web ESILV">1: <img src="/assets/img/DOM-example.a76141e9.png" alt="Representation DOM">
​
length: 2<prototype>: HTMLCollectionPrototype { item: item(), namedItem: namedItem(), length: Getter,}

C'est-à-dire la liste des éléments images de cette page.

# Récupérer les éléments du DOM

La manipulation des éléments du DOM nécessite d'abord de récupérer ces éléments. L'API DOM fournit plusieurs méthodes pour cela. Regardons celles que nous utiliserons le plus.

# document.getElementById()

Sur cette page, si vous tapez ceci dans la console du navigateur :

const anH2 = document.getElementById('l-objet-document')
console.dir(anH2)

anH2 est un objet représentant l'élement h2 ayant dans son attribut id la valeur 'l-objet-document'

Vous obtiendrez une sortie ressemblant à ceci :

h2#l-objet-document
​
accessKey: ""
accessKeyLabel: ""
align: ""
assignedSlot: null
attributes: NamedNodeMap [ id="l-objet-document" ]
baseURI: "http://localhost:8080/dom/#le-dom-document-object-model"
childElementCount: 2
childNodes: NodeList(3) [ a.header-anchor, #text, code
]
children: HTMLCollection { 0: a.header-anchor, 1: code
, length: 2 }
classList: DOMTokenList []
className: ""
clientHeight: 111
clientLeft: 0
clientTop: 0
clientWidth: 497
contentEditable: "inherit"
contextMenu: null
dataset: DOMStringMap(0)
dir: ""
draggable: false
firstChild: <a class="header-anchor" href="#l-objet-document">​
firstElementChild: <a class="header-anchor" href="#l-objet-document">
hidden: false
id: "l-objet-document"
innerHTML: "<a href=\"#l-objet-document\" class=\"header-anchor\">#</a> L'objet <code>document</code>"
(...)

# document.getElementsByTagname()

On peut aussi récupérer tous les éléments de la page ayant un type de balise particulier, comme h2 grâce à la méthode getElementsByTagname() (opens new window) de l'objet document :

var listOfH2 = document.getElementsByTagName('h2')

Comme évoqué plus tôt, listOfH2 sera une liste d'éléments HTML sous la forme d'un objet HTMLCollection (opens new window), mais pas un véritable Array. Ce qui veut dire qu'on ne pourra pas utiliser directement les méthodes de Array.prototype (opens new window).

Cependant, on peut facilement transformer cet objet en Array avec la méthode Array.from() (opens new window)

# document.getElementsByClassname()

On peut aussi récupérer tous les éléments de la page ayant une classe particulière, comme extra-class grâce à la méthode getElementsByClassName() (opens new window) de l'objet document :

var listOfElts = document.getElementsByClassName('extra-class')

L'objet retourné sera aussi de type HTMLCollection (opens new window)

# document.querySelector() et document.querySelectorAll()

Les méthodes précédentes sont des méthodes très anciennes, mais les besoins en manipulation du DOM ayant énormément grandi, de nouvelles méthodes ont été créées, qui sont plus pratiques. Elles nécessitent de connaître les sélecteurs CSS (opens new window), au moins ceux que nous avons vu précédemment.

document.querySelector() ne renvoie qu'un élément, quel que soit le nombre d'éléments sur la page qui correspondent au sélecteur CSS utilisé :

var firstEltWithExtraClass = document.querySelector('.extra-class') // Notez le . du début

Cette méthode renvoie un élément DOM (opens new window).

var allEltsWithExtraClass = document.querySelectorAll('.extra-class')

L'objet retourné est cette fois non pas un objet HTMLCollection mais un objet de type NodeList (opens new window), qui est aussi un Array-like, et donc aussi transformable facilement en Array avec Array.from() (opens new window).

# L'interface Element

Maintenant que nous avons savons sélectionner et récupérer les éléments, nous allons voir comment les manipuler. Les éléments DOM sont de plusieurs types et leurs propriétés changent en fonction de cela.

# Le texte des éléments

# La propriété innerText

On peut récupérer le texte d'un élément avec la propriété innerText des éléments :

var h1 = document.querySelector('h1')
var titleText = h1.innerText
console.log(titleText) // #
                      // Introduction au DOM

Cette propriété récupère tout le texte de l'élément, même le texte des éléments qui sont imbriqués :

var sidebarText = document.querySelector('.sidebar').innerText
console.log(sidebarText) /*
                           "Home
                           Intro
                           Chapitres 

                           Introduction au DOM

                           Le DOM : Document Object Model
                           L'objet document
                           Récupérer les éléments du DOM
                           La méthode document.getElementById
                           La méthode document.getElementsByTagname()
                           La méthode document.getElementsByClassname()
                           Les méthodes document.querySelector() et document.querySelectorAll()
                           L'interface Element
                           Le texte des éléments"
                        ​*/

Il est possible de changer le texte facilement avec cette propriété :

var h1 = document.querySelector('h1')
h1.innerText = 'Nouveau texte sans intérêt'

Si ce code est exécuté sur une page en cours (qui a une balise h1), le texte sera remplacé.

# La propriété textContent

La propriété textContent est similaire, à 2 nuances près :

  • Elle va retourner tout le texte, même celui qui n'est pas visible par l'utilisateur, comme ceux dans les éléments <script> ou dans les éléments avec display: none
  • Elle va garder le formatage et les espaces blancs

# La propriété innerHTML

La propriété innerHTML (attention à la casse : HTML est tout en majuscule) des éléments permet de retourner et de modifier le contenu de l'élément.

var h1 = document.querySelector('h1')
var inH1 = h1.innerHTML

console.log(inH1) // <a href="#introduction-au-dom" class="header-anchor">#</a> Introduction au DOM

On peut affecter une nouvelle valeur à cette propriété, et comme pour innerText, le résultat sera visible immmédiatement. La différence est qu'on peut y mettre du HTML et qu'il sera interprété comme tel.

Voici un exemple :

var h1 = document.querySelector('h1')
h1.innerHTML = 'Je peux mettre du <em>HTML</em> !'

Il existe d'autres moyens d'insérer de nouveaux éléments, de les remplacer et de les effacer que d'utiliser innerHTML, nous le verrons.

# Récupérer la valeur d'un champ d'entrée utilisateur (input)

Les éléments de type input n'ont pas de HTML ni de texte à l'intérieur, il faut donc utiliser une autre propriété pour récupérér leur valeur : value.

La propriété value est modifiable :

 loginElt.value = 'nouvelle valeur'

# Un mot sur les types checkbox et radio

Les input de type checkbox et radio auront toujours la même valeur, il faudra donc non pas voir la valeur de value, mais la valeur de checked, c'est-à-dire voir s'ils sont cochés.

# Les événements

(... Suite en cours d'écriture).