Javascript parentNode, childNodes, firstChild, nextSibling

parent node, child node, first child: wenn querySelector und getElementById nichts bringt

childNodes, firstChild und nextSilbling greifen auf Elemente zu, die nicht direkt durch Methoden wie getElementById, getElementsByName oder querySelector erreicht werden und finden jedes Element im DOM auch ohne ID und class-Attribut.

Auf das HTML-Markup darf sich niemand verlassen – immer wieder muss das Script mit nodeType und nodeName prüfen, welcher Elementtyp hier tatsächlich vorliegt, denn auch Kommentare, Zeilenumbrüche und Leerzeichen im HTML-Code sind Elemente und werden als Kind- oder Nachbarknoten interpretiert.

Diese Methoden erfordern einen Check der Fundstellen, denn sie erreichen alle Arten von Knoten:

  • Zeilenumbrüche können als neuer Knoten gelesen werden,
  • Leerzeichen zwischen den HTML-Tags,
  • HTML-Kommentare.

childNodes, firstChild, lastChild, nextSibling, previousSibling und parentNode sind alte Methoden aus der Frühzeit des DOM. Eben weil sie nicht nur echte Elemente, sondern auch Füllmaterial erreichen, sind sie um die präzisieren Methoden children, firstElementChild et.al. ergänzt worden.

Die alten Methoden lohnen sich nur, wenn tatsächlich auch leere Knoten aus dem HTML-Markup eine Rolle spielen.

childNodes

Javascript childNodes gibt ein NodeList Object aller Kindknoten von node zurück. Eine NodeList sieht aus wie ein Array, ist aber kein Array, sondern eine geordnete Liste von Nodes – die Nodes erscheinen in der Liste nach ihrer Position im Markup.

<div id="slides">
   <!-- Erstes Bild der Slideshow -->
   <figure>
      <img src="slide-01.png" width="807" height="236" alt=" " />
   </figure>
…
   <figure>
      <img src="slide-03.png" width="807" height="236" alt=" " />
   </figure>
</div>
Javascript childNodes Beispiel
Javascript childNodes Beispiel
Javascript childNodes Beispiel

Ein normaler for-loop läuft durch alle Fundstellen:

var elems = document.getElementById('slides').childNodes;
var text = '';

for (var i=0; i<elems.length; i++) {
   text += ' NodeName ' +  elems[i].nodeName + '<br>';
}
document.getElementById('status').innerHTML = text;

Das Skript sammelt alle Childnodes des Elements mit der id slides in einer NodeList elems.

NodeList mit foreach

Mit ECMAScript 2015 könnten wir mit forEach auch auf die Elemente einer NodeList zugreifen. foreach erspart die Abfrage nach der Anzahl der Elemente in der NodeList. Aber so weit ist es noch nicht. forEach wird von IE11 und älteren Versionen von Internet Explorer so noch nicht unterstützt. Erst Microsoft Edge hat ECMAScript 2015 mit forEach für NodeLists an Bord.

const elems = document.getElementById('slides').childNodes;

elems.forEach (function (item, index) {
   console.log( index + " nodeType " + item.nodeType + " nodeName " + item.nodeName );
});

Polyfill für IE11 Quelle: bob-lee / polyfill-ie11-nodelist-foreach.js

hasChildNodes

Javascript has Child Nodes gibt true zurück, wenn node Kindknoten hat und false, wenn der Knoten node keine Kindknoten hat.

<div id="noChilds"></div>

Das Skript prüft mit hasChildNodes, ob der Knoten mit der id noChilds Kinder hat.

if (document.getElementById('noChilds')) {
   if (document.getElementById('noChilds').hasChildNodes === true) {
      document.querySelector('.noChildres').innerHTML = "#noChilds hat childNodes ";
   } else {
      document.querySelector('.noChildres').innerHTML = "#noChilds hat keine childNodes ";
   }
}

firstChild / lastChild

Javascript firstChild gibt den ersten Kindknoten von node zurück.

Javascript lastChild gibt den letzten Kindknoten von node zurück.


<div id="kong">
    <svg>…</svg>
</div>

Das Skript prüft zuerst, ob ein Element mit der ID "kong" existiert und falls das Element existiert, ob das Element Kindknoten hat. Wenn das Element tatsächlich Kindknoten hat, gibt das Skript den Namen des ersten Kindknotens aus.

if (document.getElementById('kong') ) {
   var kong = document.getElementById('kong');
   if (kong.hasChildNodes) {
      document.querySelector('.fcres').innerHTML = 
         'firstChild: ' + kong.firstChild.nodeName + 
         '<br>firstElementChild: ' + kong.firstElementChild.nodeName;
   } else {
      document.querySelector('.fcres').innerHTML = 
      kong.nodeName + " hat keine Kindknoten";
   }
}

lastChild

Javascript lastChild gibt den letzten Kindknoten von node zurück

  • Montag
  • Dienstag
  • Mittwoch
<ul id="thisUl"><li>Montag</li><li>Dienstag</li><li>Mittwoch</li></ul>

Das Skript prüft, ob der Knoten mit der id thisUl Kindknoten hat (if (node.hasChildNodes))und wenn ja, dann gibt das Skript den Namen des letzten Kindknotens aus: node.lastChild.nodeName. Das letzte LI-Element erwischt das Skript aber nur zuverläßig, weil die Tags des UL-Elements ohne Leerraum in einer Zeile stehen.

if (document.getElementById('thisUl')) {
   var node = document.getElementById('thisUl');
   if (node.hasChildNodes) {
      document.querySelector('.resLast').innerHTML = 
         'Letzer Child Node: ' + node.lastChild.nodeName;
   } else {
      document.querySelector('.resLast').innerHTML = 
         'Letzer Child Node: Hat keine childNode';
   }
} else {
   document.querySelector('.resLast').innerHTML = 
      'Kein Element "thisUl" gefunden';
}

nextSibling / previousSilbling

Javascript nextSibling gibt den nächsten Knoten auf derselben Ebene zurück – einen Knoten, der am selben Elternknoten wie node hängt.

Javascript previousSibling gibt den vorangehenden Knoten auf derselben Ebene zurück – einen Knoten, der am selben Elternknoten wie node hängt.

  • Montag
  • Dienstag
  • Mittwoch
<ul id="list">
   <li>Montag</li>
   <li>Dienstag</li>
   <li>Mittwoch</li>
</ul>

nextSibling und previousSibling liefern jede Art von Knoten: text nodes, comment nodes, Leerzeichen, Tabularen oder Zeilenumbrüche. Wenn man sicher gehen will, das nur Element-Nodes aufgenommen werden, muss entweder der Typ des gefundenen Knotens überprüft oder nextElementSibling / prevElementSibling verwendet werden.

var node = document.getElementById('list2');
var text = '';
   if (node.hasChildNodes) {
      node = node.firstChild; 	
      while (node.nextSibling) {
         text = text + node.nodeName + ' '; 
         node = node.nextSibling;
      }
   } else {
      text = 'Knoten ' + node.nodeName + ' hat keine Kinder';
   }

Node Element oder #text?

firstChild, lastChild, nextSibling, previousSibling sind lausige Funktionen – i.d.R. suchen wir nach Element Nodes und wollen Zeilenumbrüche, Tabulatoren und Leerzeichen ignorieren.

Effizienter und zuverlässiger sind firstElementChild, lastElementChild, previousElementSibling, die von älteren Browsern (IE erst ab Version 9) noch nicht unterstützt wurden.

childnodes nextSibling