Find closest ancestor of a clicked element from given array

I’m trying to get the closest ancestor element to a clicked element, from an array of provided elements. When a user clicks on a tab, I need to find out where on the page that tab is.

I have something kind of working, however this script thinks main is the closest tag, when it should be article.

If I put article before main in the array it works just fine, however I wan’t this to work regardless of array order. Any ideas?

// Tab Click
var tabs = Array.from(document.querySelectorAll('details.company-details'));

function handleTabClick(e) {

  var tabNode = e.target;
  tabLabel = tabNode.innerText;

  const tgt = e.target;
  var location;
  var elements = ['section', 'header', 'main', 'nav', 'article'];

  for (let element of elements) {
    if (tgt.closest(element)) {
      location = element;
      break;
    };
  }

  console.log(location);
};

tabs.forEach(function(tab) {
  tab.addEventListener('click', handleTabClick);
});
<main class="company-main-wrapper" id="maincontent">
  <article>
    <div class="company-grid-row">
      <div class="company-grid-column-two-thirds">
        <div class="company-page-content">
          <div class="block-expander">
            <details class="company-details company-expander" company-polyfilled="true" id="company-details0" open="">
              <summary class="company-details__summary" role="button" aria-controls="company-details__text0" tabindex="0" aria-expanded="true">
                <span class="company-details__summary-text">
                                        sampoe page
                                    </span>
              </summary>
            </details>
          </div>
        </div>
      </div>
    </div>
  </article>
</main>

10 thoughts on “Find closest ancestor of a clicked element from given array”

  1. See the comments inline below:

    // Don't need Array.from() because the node list returned from 
    // .querySelectorAll() supports .forEach().
    document.querySelectorAll('details.company-details').forEach(function(tab) {
      tab.addEventListener('click', handleTabClick);
    });
    
    var elements = ['section', 'header', 'main', 'nav', 'article'];
    
    let found = false;
    let parent = null;
    
    function handleTabClick(e) {
      // Start at the parent of the tab
      parent = this.parentNode;  
      
      // Keep looping until we find an ancestor that matches
      while (found === false){ 
        // Check the name of the parent element to see if its lower
        // cased name is in the array.
        if(elements.includes(parent.nodeName.toLowerCase())){
          found = true;  // Found a match
        } else {
          // No match. Get the next parent and keep looping
          parent = getParent(parent);
        }
      }
      console.log(parent);
    };
    
    function getParent(element){
      return element.parentNode;
    }
    <main class="company-main-wrapper" id="maincontent">
      <article>
        <div class="company-grid-row">
          <div class="company-grid-column-two-thirds">
            <div class="company-page-content">
              <div class="block-expander">
                <details class="company-details company-expander" company-polyfilled="true" id="company-details0" open="">
                  <summary class="company-details__summary" role="button" aria-controls="company-details__text0" tabindex="0" aria-expanded="true">
                    <span class="company-details__summary-text">
                                            sampoe page
                                        </span>
                  </summary>
                </details>
              </div>
            </div>
          </div>
        </div>
      </article>
    </main>
    Reply

Leave a Comment