Tree Show Active Page – JavaScript – SitePoint Forums

This W3Schools JS/CSS/HTML tree structure works great for a navigation menu – How To – Tree
Except that each time a page loads, the tree is completely collapsed.
JS recognizes the active page because it bolds the text of the active page and removes the link from the page.
How can JS also expand the tree from the active page to the active page so users can see where they are in the tree?
For example, on the W3Schools example at the link above, when the “Black Tea” page loads, the tree should expand like this – Beverages > Water Coffee Tea > Black Tea White Tea Green Tea (with black tea in bold, no link). Green tea should not expand.


First, a bit of refactoring to allow reuse of the element click function:

function toggleItem(item) {
  item.parentElement.querySelector(".nested").classList.toggle("active");
    item.classList.toggle("caret-down");
}
...
  toggler[i].addEventListener("click", function itemClickHandler(evt) {
    toggleItem(evt.target);
  });

Mark one or more items as visible:

          
  • White Tea
  • Get all visible items:

    var treeTop = document.querySelector("#myUL");
    var visibleItems = treeTop.querySelectorAll(".visible");
    

    Go through each of these elements that should be visible:

    visibleItems.forEach(function (item) {
      while (item !== treeTop) {
        item = item.parentNode;
      }
    });
    

    When traversing the DOM tree from a visible element, if you find that it is in a closed group:

    function isClosedGroup(el) {
      var isNestedGroup = el.classList.contains("nested");
      if (isNestedGroup) {
        var caret = el.previousElementSibling;
        var isOpenGroup = caret.classList.contains("caret-down");
        return !isOpenGroup;
      }
    }
    ...
      while (item !== treeTop) {
        if (isClosedGroup(item)) {
          ...
        }
        item = item.parentNode;
      }
    

    Then show this group:

    function showGroup(item) {
      var caret = item.parentNode.querySelector(".caret");
      toggleItem(caret);
    }
    ...
      while (item !== treeTop) {
        if (isClosedGroup(item)) {
          showGroup(item);
        }
        item = item.parentNode;
      }
    

    Here is the updated script code in full:

    function toggleItem(item) {
      item.parentElement.querySelector(".nested").classList.toggle("active");
        item.classList.toggle("caret-down");
    }
    var toggler = document.getElementsByClassName("caret");
    var i;
    
    for (i = 0; i < toggler.length; i++) {
      toggler[i].addEventListener("click", function itemClickHandler(evt) {
        toggleItem(evt.target);
      });
    }
    
    
    function isClosedGroup(el) {
      var isNestedGroup = el.classList.contains("nested");
      if (isNestedGroup) {
        var caret = el.previousElementSibling;
        var isOpenGroup = caret.classList.contains("caret-down");
        return !isOpenGroup;
      }
    }
    function showGroup(item) {
      var caret = item.parentNode.querySelector(".caret");
      toggleItem(caret);
    }
    
    var treeTop = document.querySelector("#myUL");
    var visibleItems = treeTop.querySelectorAll(".visible");
    visibleItems.forEach(function (item) {
      while (item !== treeTop) {
        if (isClosedGroup(item)) {
          showGroup(item);
        }
        item = item.parentNode;
      }
    });
    

    Hopefully this way of presenting information makes it easier to work and understand what each part is doing.

    For the active page, you’ll also need some code before it that sets one of the elements to visible.

    To achieve this, we want to get the name of the page:

    function getPageName(pathname) {
      var regex = /(w+).asp/;
      var match = regex.exec(pathname);
      return match[1];
    }
    ...
    var pageName = getPageName(location.pathname);
    

    Each of the elements of the page can have an identifier which corresponds to the name of the page:

              
  • Black Tea
  • White Tea
  • Try It
  • And with this page name, we want to find the appropriate element with the same name:

    function findMatchingItem(container, pagename){
      var items = container.querySelectorAll("li");
      return Array.from(items).find(function (item) {
        return item.dataset.id === pagename;
      });
    }
    ...
    var treeTop = document.querySelector("#myUL");
    var pageName = getPageName(location.pathname);
    var item = findMatchingItem(treeTop, pageName);
    item.classList.add("visible");
    

    The complete code to use on the tryit page is as follows:

    
    
    
    
    
    
    
    
    

    Tree View

    A tree view represents a hierarchical view of information, where each item can have a number of subitems.

    Click on the arrow(s) to open or close the tree branches.

    • Beverages
      • Water
      • Coffee
      • Tea
        • Black Tea
        • White Tea
        • tryit
        • Green Tea
          • Sencha
          • Gyokuro
          • Matcha
          • Pi Lo Chun

    James S. Joseph