Home > Enterprise >  Responsive accessible navigation dropdown issue
Responsive accessible navigation dropdown issue

Time:02-26

I have a responive navigation which has a dropdown that cases me headaches. Currenlty the navigatio has a event listener mouse over for desktop and on devices has a click event that adds a .is-active class.

For some reason the events aren't working. I get this error. Uncaught ReferenceError: j is not defined.

I can't figure it out. I leave the code below. hopefully you gus can help me out to find the issue.

const navBlocks = document.querySelectorAll(".nav-container");
const mediaQuery = window.matchMedia("(min-width: 900px)");
const navBp = "(min-width: 900px)";

let isMenuOpen = false;

for (var i = 0; i < navBlocks.length; i  ) {
  const menu = navBlocks[i].querySelector(".sliding-nav .nav-wrap");
  const nav = navBlocks[i].querySelector(".sliding-nav");
  let btn = navBlocks[i].querySelector(".nav-cta");
  let navLinks = navBlocks[i].querySelectorAll(".sliding-nav .nav-items > li");
  //let isSubNavLink = navBlocks[i].querySelector(".has-nav-panel");

  btn.onclick = function (e) {
    e.preventDefault();
    isMenuOpen = !isMenuOpen;
    btn.setAttribute("aria-expanded", String(isMenuOpen));
    menu.hidden = !isMenuOpen;

    if (isMenuOpen) {
      nav.classList.add("is-open");
      document.body.classList.add("is-no-scroll", "is-fixed");
      //console.log(isMenuOpen);
    } else {
      nav.classList.remove("is-open");
      document.body.classList.remove("is-no-scroll", "is-fixed");
      //console.log(!isMenuOpen);
    }
  };

  Array.prototype.forEach.call(navLinks, function (el, i) {
    var currentNavLink = navLinks[i];

    currentNavLink.addEventListener("click", function () {
      megaNavClickAndTouchHandler(navLinks, currentNavLink);
    });

    currentNavLink.addEventListener("mouseover", function () {
      megaNavMouseOverHandler(navLinks, currentNavLink, navBp);
    });

    currentNavLink.addEventListener("mouseleave", function () {
      megaNavMouseLeaveHandler(navLinks, currentNavLink, navBp);
    });

    megaNavResetOnBreakPoint(navLinks, currentNavLink, mediaQuery);
  });

  function megaNavResetOnBreakPoint(elements, currentElement, mqNav) {
    if (matchMedia) {
      var navigationBar = currentElement.closest(".header");
      var navigationItems = currentElement.closest(".sliding-nav");

      mqNav.addListener(function () {
        if (mqNav.matches) {
          document.querySelectorAll("body")[0].classList.remove("is-no-scroll");
          navigationBar.classList.remove("is-active");
          navigationItems.classList.remove("is-active");
          navigationBar
            .querySelectorAll(".burger")[0]
            .classList.remove("is-active");
          megaNavClosePanels(elements);
        } else {
          megaNavClosePanels(elements);
        }
      });
    }
  }

  function megaNavClickAndTouchHandler(elements, currentElement) {
    var isSubNavLink = currentElement.classList.contains("has-nav-panel");
    var isSubNavLinkActive = currentElement.classList.contains("is-active");
    var navBarContainer = currentElement.closest(".header");

    if (!isSubNavLink) {
      window.location = currentElement.firstElementChild.getAttribute("href");
    } else if (isSubNavLink && !isSubNavLinkActive) {
      megaNavClosePanels(elements);
      currentElement.classList.add("is-active");
    } else {
      megaNavClosePanels(elements);
    }
  }
  function megaNavClosePanels(elements) {
    for (j = 0; j < elements.length; j  ) {
      if (elements[j].classList.contains("has-nav-panel")) {
        elements[j].classList.remove("is-active");
      }
    }
  }
  function megaNavMouseOverHandler(elements, currentElement, breakPoint) {
    if (window.innerWidth >= breakPoint) {
      var isSubNavLink = currentElement.classList.contains("has-nav-panel");

      megaNavClosePanels(elements);
      currentElement.classList.add("is-active");
    }
  }

  function megaNavMouseLeaveHandler(elements, currentElement, breakPoint) {
    if (window.innerWidth >= breakPoint) {
      currentElement.classList.remove("is-active");
    }
  }

  function handleTabletChange(e) {
    // Check if the media query is true

    if (e.matches) {
      console.log("desktop");
      btn.setAttribute("aria-expanded", false);
      menu.removeAttribute("hidden");
      nav.classList.remove("is-open");
      document.body.classList.remove("is-no-scroll", "is-fixed");
    } else {
      console.log("mobile");
      btn.setAttribute("aria-expanded", false);
    }
  }

  // Register event listener
  mediaQuery.addListener(handleTabletChange);

  // Initial check
  handleTabletChange(mediaQuery);

  // TRAP TAB INSIDE NAV WHEN OPEN
  nav.addEventListener("keydown", (e) => {
    // abort if menu isn't open or modifier keys are pressed
    if (!isMenuOpen || e.ctrlKey || e.metaKey || e.altKey) {
      return;
    }

    // listen for tab press and move focus
    // if we're on either end of the navigation
    const menuLinks = menu.querySelectorAll(".nav-link");
    if (e.keyCode === 9) {
      if (e.shiftKey) {
        if (document.activeElement === menuLinks[0]) {
          menuToggle.focus();
          e.preventDefault();
        }
      } else if (document.activeElement === menuToggle) {
        menuLinks[0].focus();
        e.preventDefault();
      }
    }
  });
}

demo in codepen, please fork it to modify

CodePudding user response:

The code should be modified:

  • let j
  • breakPoint is not a number

const navBlocks = document.querySelectorAll(".nav-container");
const BREAKPOINT = 900
const mediaQuery = window.matchMedia(`(min-width: ${BREAKPOINT}px)`);
const navBp = `(min-width: ${BREAKPOINT}px)`;

let isMenuOpen = false;

for (var i = 0; i < navBlocks.length; i  ) {
  const menu = navBlocks[i].querySelector(".sliding-nav .nav-wrap");
  const nav = navBlocks[i].querySelector(".sliding-nav");
  let btn = navBlocks[i].querySelector(".nav-cta");
  let navLinks = navBlocks[i].querySelectorAll(".sliding-nav .nav-items > li");
  //let isSubNavLink = navBlocks[i].querySelector(".has-nav-panel"); 

  btn.onclick = function(e) {
    e.preventDefault();
    isMenuOpen = !isMenuOpen;
    btn.setAttribute("aria-expanded", String(isMenuOpen));
    menu.hidden = !isMenuOpen;

    if (isMenuOpen) {
      nav.classList.add("is-open");
      document.body.classList.add("is-no-scroll", "is-fixed");
      //console.log(isMenuOpen);
    } else {
      nav.classList.remove("is-open");
      document.body.classList.remove("is-no-scroll", "is-fixed");
      //console.log(!isMenuOpen);
    }
  };

  Array.prototype.forEach.call(navLinks, function(el, i) {
    var currentNavLink = navLinks[i];

    currentNavLink.addEventListener("click", function() {
      megaNavClickAndTouchHandler(navLinks, currentNavLink);
    });

    currentNavLink.addEventListener("mouseover", function() {
      megaNavMouseOverHandler(navLinks, currentNavLink, BREAKPOINT);
    });

    currentNavLink.addEventListener("mouseleave", function() {
      megaNavMouseLeaveHandler(navLinks, currentNavLink, BREAKPOINT);
    });

    megaNavResetOnBreakPoint(navLinks, currentNavLink, mediaQuery);
  });

  function megaNavResetOnBreakPoint(elements, currentElement, mqNav) {
    if (matchMedia) {
      var navigationBar = currentElement.closest(".header");
      var navigationItems = currentElement.closest(".sliding-nav");

      mqNav.addListener(function() {
        if (mqNav.matches) {
          document.querySelectorAll("body")[0].classList.remove("is-no-scroll");
          navigationBar.classList.remove("is-active");
          navigationItems.classList.remove("is-active");
          navigationBar
            .querySelectorAll(".burger")[0]
            .classList.remove("is-active");
          megaNavClosePanels(elements);
        } else {
          megaNavClosePanels(elements);
        }
      });
    }
  }

  function megaNavClickAndTouchHandler(elements, currentElement) {
    var isSubNavLink = currentElement.classList.contains("has-nav-panel");
    var isSubNavLinkActive = currentElement.classList.contains("is-active");
    var navBarContainer = currentElement.closest(".header");

    if (!isSubNavLink) {
      window.location = currentElement.firstElementChild.getAttribute("href");
    } else if (isSubNavLink && !isSubNavLinkActive) {
      megaNavClosePanels(elements);
      currentElement.classList.add("is-active");
    } else {
      megaNavClosePanels(elements);
    }
  }

  function megaNavClosePanels(elements) {
    for (let j = 0; j < elements.length; j  ) {
      if (elements[j].classList.contains("has-nav-panel")) {
        elements[j].classList.remove("is-active");
      }
    }
  }

  function megaNavMouseOverHandler(elements, currentElement, breakPoint) {
    console.log('here', breakPoint)
    if (window.innerWidth >= breakPoint) {
      var isSubNavLink = currentElement.classList.contains("has-nav-panel");

      megaNavClosePanels(elements);
      currentElement.classList.add("is-active");
    }
  }

  function megaNavMouseLeaveHandler(elements, currentElement, breakPoint) {
    if (window.innerWidth >= breakPoint) {
      currentElement.classList.remove("is-active");
    }
  }

  function handleTabletChange(e) {
    // Check if the media query is true

    if (e.matches) {
      console.log("desktop");
      btn.setAttribute("aria-expanded", false);
      menu.removeAttribute("hidden");
      nav.classList.remove("is-open");
      document.body.classList.remove("is-no-scroll", "is-fixed");
    } else {
      console.log("mobile");
      btn.setAttribute("aria-expanded", false);
    }
  }

  // Register event listener
  mediaQuery.addListener(handleTabletChange);

  // Initial check
  handleTabletChange(mediaQuery);

  // TRAP TAB INSIDE NAV WHEN OPEN
  nav.addEventListener("keydown", (e) => {
    // abort if menu isn't open or modifier keys are pressed
    if (!isMenuOpen || e.ctrlKey || e.metaKey || e.altKey) {
      return;
    }

    // listen for tab press and move focus
    // if we're on either end of the navigation
    const menuLinks = menu.querySelectorAll(".nav-link");
    if (e.keyCode === 9) {
      if (e.shiftKey) {
        if (document.activeElement === menuLinks[0]) {
          menuToggle.focus();
          e.preventDefault();
        }
      } else if (document.activeElement === menuToggle) {
        menuLinks[0].focus();
        e.preventDefault();
      }
    }
  });
}

CodePudding user response:

Change:

function megaNavClosePanels(elements) {
    for (j = 0; j < elements.length; j  ) {
      if (elements[j].classList.contains("has-nav-panel")) {
        elements[j].classList.remove("is-active");
      }
    }
}

to:

function megaNavClosePanels(elements) {
    for (let j = 0; j < elements.length; j  ) {
      if (elements[j].classList.contains("has-nav-panel")) {
        elements[j].classList.remove("is-active");
      }
    }
}

You are getting that error because the running variable, j in this case, has not been declared and you are using strict directive somewhere (which prevents the use of undeclared variables).

  • Related