innerHTML versus createTextNode ?


#1

Bonjour,

Je suis débutant en JS (mais pas en codage). La base du langage ça va, les subtilités cele serra pour plus tard. Là je m’attaque au cœur du sujet : l’interaction avec le DOM. Tout cela me semble vraiment très sympa et pas si compliqué. Sauf que de temps en temps on constate qu’il y a plusieurs méthodes pour faire (en apparence) la même chose. Un exemple : modifier le contenu d’un objet du DOM. Que préfèrez vous entre innerHTML et createTextNoode ? Et pourquoi ?

Cdlt,
PB


#2

Vrai question

Ces deux éléments ne jouent pas dans la même cour. En fait, ta question c’est de savoir : « quelle est la différence entre :

document.createElement et <HTMLElement>.innerHTML

ou entre

document.createTextNode et <HTMLElement>.textContent »

Comprendre les différents type de noeud

Commençons par la différence entre un Node, un Text et un HTMLElement.

Un élément HTMLElement n’est autre qu’un Element qui n’est autre qu’un Node pour le dire autrement : HTMLElement est un cas particulier de Node.

De la même manière, Text est un cas particulier de Node.

Ceci est possible grâce à la chaîne des prototypes de chaque objet, mais comme tu l’as dit, pour les subtilités, tu verras plus tard. Voyons le code ci-dessous pour comprendre :

var text = document.createTextNode("Je suis un node Text. Je contiens du texte");
console.log(text instanceof Node) // true
console.log(text instanceof Text) // true
console.log(text instanceof Comment) // false
console.log(text instanceof HTMLElement) // false
console.log(text.nodeType) // 3

var comment = document.createComment("Je suis un commentaire !");
console.log(comment instanceof Node) // true
console.log(comment instanceof Text) // false
console.log(comment instanceof Comment) // true
console.log(comment instanceof HTMLElement) // false
console.log(comment.nodeType) // 8

var html = document.createElement("div");
console.log(html instanceof Node) // true
console.log(html instanceof Comment) // false
console.log(html instanceof Text) // false
console.log(html instanceof HTMLElement) // true
console.log(html instanceof HTMLDivElement) // true
console.log(html instanceof HTMLSpanElement) // false
console.log(html.nodeType) // 1

En clair, la représentation du code HTML suivant :

<div><strong>Bonjour</strong>Salut<!--Tout les autres types de salutation--></div>

sous forme de DOM est la suivante :

HTMLDivElement (Node typeNode 1)
├─ HTMLStrongElement (Node typeNode 1)
│   └─ Text (Node typeNode 3)
├─ Text (Node typeNode 3)
└─ Comment (Node typeNode 8)

Réponse

Les différences principales maintenant c’est que :

  • document.createElement ne prend en paramètre que le nom du tag puisque le contenu du tag n’a pas d’existence car c’est en fait une liste de sous Node (NodeList). Cet HTMLElement n’est pas présent dans le DOM principal et il faudra l’ajouter ultérieurement avec l’une des nombreuses méthodes d’ajout de Node/HTMLElement.

  • document.createNodeText ne créé en réalité qu’un seul noeud même si tu écris du HTML dedans, c’est en fait du texte brut. Aussi je suis <strong>fort</strong> ! est un noeud textuel contenant les caractères < et > qui ne sont pas interprété comme des balises. Comme le cas précédent, ce Node de type texte n’est pas dans le DOM principal, il faudra l’ajouter manuellement.

  • Venons en maintenant à <HTMLElement>.innerHTML qui est une méthode accessible depuis n’importe quel HTMLElement. Celui ci « transforme » une chaîne de caractère (String) en DOM local et l’injecte directement au DOM principal sous le HTMLElement qui a appelé la méthode en supprimant tous les autres éléments présent avant.

  • En ce qui concerne <HTMLElement>.textContent, celui-ci prend une chaîne de caractère et le transforme en un noeud de type texte (3) et l’ajoute en tant qu’enfant de l’élément HTMLElement qui a appelé la méthode.

Différence de manipulation et contexte

Il faut comprendre qu’on ne peut pas directement ajouter un document.createTextNode avec un <HTMLElement>.textContent au DOM principal car cette méthode prend une String et pas un Text (ou Node).
C’est la même chose avec document.createElement et <HTMLElement>.innerHTML

Dans ce cas ou utilisera plutôt <HTMLElement>.appendChild qui lui prend un Node en paramètre et l’ajoute à la fin des enfants. On prendra alors soin de raser la liste des éléments enfant avant si on veut « remplacer » le contenu :

Aussi les codes suivant son équivalent :

Code avec createElement, createComment et createTextNode

var div = document.createElement("div"),
      strong = document.createElement("strong"),
      textStrong = document.createTextNode("Bonjour"),
      text = document.createTextNode("Salut"),
      comment = document.createComment("Tout les autres types de salutation");

strong.appendChild(textStrong)
div.appendChild(strong);
div.appendChild(text);
div.appendChild(comment);
document.body.innerHTML = "";
document.body.appendChild(div);

ou code avec innerHTML

document.body.innerHTML = "<div><strong>Bonjour</strong>Salut<!--Tout les autres types de salutation--></div>";

Le premier est plus programmatique alors que le second est plus « templatique ».

L’avantage de la première approche est pour la manipulation futur qui est possible, je peux changer Bonjour en Hello facilement :

strong.textContent = "Hello";

alors qu’avec le template, je dois aller trouver la référence dans le DOM avant puisque je n’est pas créé programmatiquement mon arbre :

document.getElementsByTagName("strong")[0].textContent = "Hello";

J’espère t’avoir aidé.


#3

Merci pour la réponse. Oui c’est plus clair. La représentation arborescente du DOM est vraiment très parlante (il me semble que c’est le cas avec un peu tous les langages à balises… mais je ne suis pas sûr de moi).

Et concernant les différentes manières de coder “programmatique” versus “templatique”, je comprends tout à fait l’intérêt de la première version. Un peu plus long, mais plus “carré”, tous les objets ont des noms,etc. Alors que dans le deuxième exemple, en caricaturant un peu, on pourrait presque se demander à quoi sert JavaScript. Autant écrire directement en HTML.

Encore merci. Je continue encore un peu à mieux comprendre les manipulations “basiques” des éléments du DOM puis j’attaque jQuery (certains disent que c’est dépassé, je ne les écoute pas, j’essaye quand même !).

Pierre