Hide submenus when I scroll page

I need to do this functionality in navigation menu - submenu lists. When scrolls down the page, the submenu is to hide

http://www.marypieroszkiewicz.com/3n_solution/

This is my code for menu-submenu

      const menu = document.querySelector(".menu");
      const links = menu.querySelectorAll("a:not(.js-anchor--link)");
    
      for (const el of links) {
        el.addEventListener("click", function (e) {
          e.preventDefault();
    
          const ul = this.nextElementSibling;
          if (ul !== null) {
            ul.classList.toggle("menu-submenu--show");
          }
    
    
          let par = this.parentElement;
          while (true) {
            if (par.parentElement.classList.contains("menu")) break;
            par = par.parentElement;
          }
    
          console.log(par)
          const mainLiChild = menu.children;
          for (const li of mainLiChild) {
            if (li !== par) {
              li.querySelectorAll(".menu-submenu").forEach(el => el.classList.remove("menu-submenu--show"));
            }
          }
        })
      }

When you scroll, which menu exactly do you want to hide? Is it the entire header menu, or is it just the menu that appears when you click on an item?

I looked at this earlier today; the sort of “moral equivalent” solution is just:

addEventListener(
    'scroll',
    _ => [...document.querySelectorAll('.menu-submenu--show')]
        .forEach(
            e => e.classList.remove('menu-submenu--show')
        )
)

…plus adjustments for what exactly folks want to dismiss or have happen.

1 Like

@krilnon Yes, this is it. Truly thank you for your great solution :+1:t2::slightly_smiling_face:

One tiny addition is that, unlike getElementsByClassName, querySelectorAll returns a NodeList, and NodeList objects have a forEach built in. This means spreading to an array is not needed if you need forEach (note that other array methods like map are not built in, so you may want to spread then, or manually call map on the list via call()).

addEventListener(
    'scroll',
    _ => document.querySelectorAll('.menu-submenu--show')
        .forEach(
            e => e.classList.remove('menu-submenu--show')
        )
)

getElementsByClassName return HTMLCollections which do not have a forEach. They are, like NodeLists, array-like, though, so you can ultimately use array methods on them (more on that in the array-likes tip of the day: JavaScript Tips of the Day ).

1 Like

Fair enough; I spend enough of my time programming in other languages that all I remembered was that querySelectorAll has an unpredictable (by me, not docs) subset of behavior that I’d expect from an array.