HTMLCollection
Die alten Methoden des DOM – getElementsByTagName () und getElementsByClassName () geben eine HTMLCollection zurück, eine Liste oder Sammlung von Elementen. Eine HTMLCollection hat eine length-Eigenschaft, die einzelnen Elemente können über einen Index angesprochen werden und der Index beginnt mit 0. Die Sammlung reagiert live auf Änderungen des DOM.
Eine HTMLCollection sieht also aus wie ein Array, hat einen Index wie ein Array, ist aber kein Array, so dass Array-Methoden höherer Ordnung wie forEach() nicht benutzt werden können.
getElementsByTagName
getElementsByTagName () wird mit dem Namen eines HTML-Elements als Argument aufgerufen.
const list = document.getElementsByTagName ("h2"); console.log (list);
▼ HTMLCollection
0 <h2>HTMLCollection</h2>
1 <h2>getElementsByTagName</h2>
2 <h2>getElementsByClassNaem</h2>
…
▼ HTMLCollection Prototype
▶ █ constructor: function ()
█ item([index])
█ length
█ Symbol(Symbol.iterator)()
█ Symbol(Symbol.toStringTag): "HTMLCollection"
Da die Liste einen Index hat, spricht der Index einzelne Elemente der Liste gezielt an.
console.log (list[1]);
Die for-Anweisung iteriert über die Liste – nicht nur for i=0 …, sondern auch die jüngere Version aus ES6: for of.
Array-Methoden können bei HTMLCollections nur angewendet werden, wenn die Liste zuvor mit Array.from () in ein Array umgewandelt wird.
const arr = Array.from (list); console.log ("arr", arr);
getElementsByClassName
Auch die Methode getElementsByClassName () gibt eine dynamische HTMLCollection aller Elemente einer CSS-Klasse zurück, hat eine Länge und einen Index. Die Elemente der HTMLCollection lassen sich mit einer for-Anweisung durchlaufen, aber für Array-Methoden höherer Ordnung muss die Liste ebenfalls in ein Array umgewandelt werden.
Das Argument der Methode ist der Name einer CSS-Klasse – ohne einen Punkt.
- Savarin
- Sable
- Flan
<ul class="columns"> <li class="item"> Savarin <img src="savarin.webp" …> </li> <li class="item"> Sable <img src="sable.webp" …> </li> <li class="item"> Flan <img src="flan.webp" …></li> </ul>
const list = document.getElementsByClassName ("item");
elem.innerText liest oder überschreibt den vollständigen Inhalt. elem.innerHTML hingegen kann den Inhalt Inhalt des Elements auslesen und mit Modifikationen erneut einsetzen, dabei auch vollständige HTML-Tags mit ihren Attributen. Javascript kann auch solche eingesetzten HTML-Elemente zugreifen, denn sie sind vollwertige Elemente des DOM.
list[1].innerHTML = `Mont Blanc <img loading="lazy" src="cake-m-blanc.webp" …>`;
- Savarin
- Sable
- Flan
getElementsByName
getElementsByName ist für Formularelemente wie input type="radio" gedacht, in denen das Name-Attribut eine Gruppe von Elemente zusammenhält. Anders als getElementsByTagName und getElementsByClassName gibt getElementsByName () keine HTMLCollection, sondern eine NodeList zurück. NodeLists sind zwar ebenfalls kein Array, aber sie unterstützen Array-Methoden höherer Ordnung (forEach).
querySelectorAll vs getElementsByClassName / getElementsByTagName
Heute ziehen wir in den allermeisten Fällen querySelectorAll () vor, schon weil wir einen beliebigen CSS-Selektor als Argument einsetzen können. Zudem gibt querySelectorAll () eine NodeList zurück, die auch Array-Methoden höherer Ordnung wie forEach () zulässt.
console.log ("list", document.querySelectorAll (".demo"));
Die Konsole gibt jetzt als Typ NodeList an. Der Prototyp enthält gegenüber dem Prototyp der HTMLCollection entries(), forEach(), keys() und values().
▼ list
▼ NodeList (3)
0 <li class="demo">…</li>
1 <li class="demo">…</li>
2 <li class="demo">…</li>
▼ NodeList Prototype
▶ █ constructor: function()
█ entries()
█ forEach()
█ item(index)
█ keys()
█ length: 3
█ values()
█ Symbol(Symbol.iterator)()
█ Symbol(Symbol.toStringTag): "NodeList"
querySelector () kann nicht nur auf dem document-Objekt aufgerufen werden, sondern auf allen Elementen von document, so wie hier mit item.querySelector("img").
document.querySelectorAll(".item").forEach (item => console.log ("", item.querySelector("img").src));
Hingegen geben forEach und die Arrow Function bei dynamischen HTMLCollections eine Fehlermeldung zurück.
TypeError: items.forEach is not a function. (In 'items.forEach(function(item, index) {
console.log( item.getAttribute("title") );
})', 'items.forEach' is undefined)
NodeList vs HTMLCollection
Eine NodeList ist statisch, d.h., sie ändert sich nicht, wenn neue Elemente in die Liste eingefügt oder Elemente aus der Liste entfernt werden.
Die HTMLCollection hingegen ist dynamisch und das Einfügen oder Entfernen von Elementen ändert die Liste sofort.
const li = document.createElement('li'); const span = document.createElement ('span'); span.setAttribute('class','item'); li.appendChild(span); document.getElementById("nav").appendChild(li); console.log ("*** items.length " + items.length); //=> 4 console.log ("*** query.length " + query.length) //=> 5