Search code examples
javascripthtmldom-traversal

Why do I get undefined when I use elements from a node-list or HTML-Collection when traversing the DOM?


While traversing the DOM there are sometimes many child elements under one parent.

I can get these children as either node-lists using a querySelectorAll or I can get them as HTML-Collections by using element.children.

But when I select one to use to put in my DOM tree traversal I get undefined.

I have tried turning the node-lists and HTML-Collections into arrays and using them that way with no success. I have tried using for-of loops regular for loops and foreach loops for selecting a single element, yet always with failure undefined.

I have created a made up situation that shows this situation, although the problem is solvable without having to Traverse the DOM, you have to image that it is necessary.

  • HTML
<!DOCTYPE html>
<html lang="en">
   <head>
      <title>Testing</title>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="eric_meyer_reset_2.css" />
      <link rel="stylesheet" href="styles.css" />
   </head>
   <body>
      <div id="wrapper">
         <div id="topOfPage">
            <header>
               <h1>Random Number Generator</h1>
            </header>
            <div id="simulated RNG">
               <p>Your number is: <span id="theRandomNumber">2</span></p>
               <button type="button" id="prizeOpenButton">Press for Prize</button>
            </div>
         </div>
         <div id="bottomOfPage">
            <!-- These sections are added dynamically during the script operation -->
            <section class="joy" data-id="0">Hurray</section>
            <section class="joy" data-id="1">Hurrah</section>
            <section class="joy" data-id="2">Yay</section>
            <section class="joy" data-id="3">Congrats</section>
         </div>
      </div>
      <script src="main.js"></script>
   </body>
</html>
  • CSS
.joy {
   display: none
}
  • JavaScript
const randomNumber = document.getElementById("theRandomNumber");
const prizeButton = document.getElementById("prizeOpenButton")

let matchNumberToPrizeSection = function (event) {
   let prizeSections = document.querySelectorAll(".joy");

   let theSection = null;

   for (let i = 0; i < prizeSections.length; i++) {
      if (prizeSections[i].dataset.id === randomNumber) {
         theSection = prizeSections[i];
      }
   }

   // lets say for some reason we have to traverse the DOM
   // starting with the button going to the "theSection" above
   let winningSection = event.target.parentElement.parentElement.nextElementSibling.theSection;

   console.log(winningSection.innerHTML);
}
prizeButton.addEventListener("click", matchNumberToPrizeSection);

Solution

  • While you cannot use node-list or HTML-Collection elements directly or indirectly when you are building up a DOM traversal. What I finally found was that I can use the element before the many child elements, in my original question that was a div with id of bottomOfPage. What I had to do was find the index of the child element that I needed using the node-list elements and use that index in the parent div like this. event.target.parentElement.parentElement.nextElementSibling.children(index)