Assuming the DOM is as described in the snippet below, my requirement is to get a javascript array of all the child nodes of div. container <div id=”container”><div class="divy">...</div><div class="divy">...</div><div class="divy">...</div><div class="divy">...</div></div> During the good jQuery days, you could just do or $('.divy') $('#container').children() I was trying to do the same thing using the native DOM selector API and was in for a surprise const childDivs = document.querySelectorAll('.divy') Array.isArray(childDivs) //=> falsechildDivs.constructor.name //=> NodeList Okay let’s try one of the methods and check what is returned getElementBy% const childDivsAgain = document.getElementsByClassName('divy') Array.isArray(childDivs) //=> falsechildDivs.constructor.name //=> HTMLCollection Now what are and objects and why are we not getting the plain vanilla javascript array from these methods? NodeList HTMLCollection Let’s try to understand the difference between HTMLCollection and NodeList first. An HTMLCollection is a list of nodes. An individual node may be accessed by either ordinal index or the node’s name or id attributes. Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying document is changed. HTML Collections are “in the DOM”, whereas a NodeList is a more generic construct that may or may not be in the DOM. always A NodeList object is a collection of nodes. The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live or static based on the interface used to retrieve them Let’s test the specification with relevant code to understand more let parentDiv = document.getElementById('container') let nodeListDivs = document.querySelectorAll('.divy')let htmlCollectionDivs = document.getElementsByClassName('divy') nodeListDivs.length //=> 4htmlCollectionDivs.length //=> 4 //append new child to containervar newDiv = document.createElement('div');newDiv.className = 'divy'parentDiv.appendChild(newDiv) nodeListDivs.length //=> 4htmlCollectionDivs.length //=> 5 We can see that the HTMLCollection is literally live, in the sense, any change to DOM is updated automatically and available in the collection. Not all NodeList objects are static. For example, will return a live NodeList. document.getElementByName But remember that neither nor support the array prototype methods like or methods . Iterator methods like have been recently added though and latest browsers might support them. HTMLCollection NodeList push pop splice forEach I came to know about this difference, when I was trying to use the library to add selected components to the library dragula drag-n-drop let draggableLists = document.querySelectorAll('div.draggable')dragula(draggableLists); //will not work This will not work as expected as the constructor expects a javascript array and we are passing a NodeList to it. dragula() To convert the NodeList or HTMLCollection object to a javascript array, you can do one of the following: Use Array.from method const nodelist = document.querySelectorAll(‘.divy’)const divyArray = Array.from(nodelist) Use Array.prototype.slice const nodelist = document.querySelectorAll(‘.divy’)const divyArray = Array.prototype.slice.call(nodelist) ES6 way And I like this one. If you are using ES6, you can just use the spread operator const divyArray = […document.querySelectorAll(‘.divy’)] Now, let’s apply that to the dragula api to make it work dragula([...document.querySelectorAll('div.draggable')]) So when do you really convert NodeList to an array? Well, it depends on your usecase. If you really want an iterator to the latest updated DOM at all times, you should use the or as it is without converting it to an array. NodeList HTMLCollection If you liked this post, pls follow me on twitter for more updates..
Share Your Thoughts