skip to Main Content

I am doing an exercise and have the below html code in which I am trying to add an event listener for Element 1, Element 2, Element 3 and Element 4 to be printed when mouseover. I don’t want the event to be triggered when over their submenus (eg 2.1,4.1 etc..)

<div>
  <ul>
    <li>Element 1</li>
    <li>Element 2
      <ul>
        <li>Element 2.1</li>
        <li>Element 2.2</li>
        <li>Element 2.3</li>
        <li>Element 2.4</li>
      </ul>
    </li>
    <li>Element 3</li>
    <li>Element 4
      <ul>
        <li>Element 4.1</li>
        <li>Element 4.2</li>
        <li>Element 4.3</li>
        <li>Element 4.4</li>
      </ul>
    </li>
  </ul>
</div>

The event is being triggered no matter which element I hover over, including submenus. I have used below code:


const mainElems = document.querySelectorAll('div > ul > li:not(ul)')

function show(element, event) {
    event.stopPropagation();
    console.log(element.innerText);
}

mainElems.forEach(element => {
    element.addEventListener("mouseover", (event) => show(element, event));
});

I suspect it is because Element 2 and 4 wrap their entire contents with the a single li…does that sound right?

Is my attempt to select the main Elements and exclude their submenus with below code correct?
const mainElems = document.querySelectorAll('div > ul > li:not(ul)')

Why is the event being triggered even when selecting submenus?

2

Answers


  1. This issue you’re facing is due to the event bubbling in the DOM.

    To prevent the event from being triggered when hovering over submenus, you can use the event.target property to check if the event originated from the main li elements or their submenus. Here’s how you can modify your code:

    const mainElems = document.querySelectorAll('div > ul > li:not(ul)')
    
    function show(element, event) {
        if (event.target === element) {
            console.log(element.innerText);
        }
    }
    
    mainElems.forEach(element => {
        element.addEventListener("mouseover", (event) => show(element, event));
    });
    
    Login or Signup to reply.
  2. Instead of setting up listeners for all elements, you could check to see if element has children and only set listeners for elements without children:

      mainElems.forEach(element => {
      // only add a listener to nodes that have only 1 childNode
      if(element.childNodes.length === 1) {
        element.addEventListener("mouseover", (event) => show(element, event));
      }    
    });
    

    Also see example in codesandbox.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search