Pier-Olivier Marquis
Pier-Olivier Marquis

Reputation: 458

Elegant way of checking if one of the parentNodes has a certain class

I have a menu that expands and retracts on hover. The problem is the menu has many elements and to trigger my expand function I need to write something like below. My actual code includes more code and I was wondering if there would be a better way to do this.

var e = event.target

if(
e.parentNode.className.split(" ")[0] === "main-section" ||
e.parentNode.parentNode.className.split(" ")[0] === "main-section" ||
e.parentNode.parentNode.parentNode.className.split(" ")[0] === "main-section"){
//do somehtings}

Upvotes: 1

Views: 48

Answers (3)

kockburn
kockburn

Reputation: 17606

Use classList with a recursive function like so.

const start = document.getElementById("start");

function recursiveCheck(ele, className, limit = 3, current = 0){
   return ele.classList.contains(className) ? true : current >= limit ? false : recursiveCheck(ele.parentNode, className, limit, current + 1);
}

console.log(
  recursiveCheck(start, "test")
);
<div class="test">
  <div>
    <div id="start"><div>
  </div>
</div>

Upvotes: 0

Lab Lab
Lab Lab

Reputation: 801

Method closest() is not supported in some browsers, so I took this function for you from this answer

function findAncestor (el, sel) {
    while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
    return el;
}

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074068

In modern environments you can use the DOM's closest method:

if (e.closest(".main-section")) {
    // One was found...
}

It looks at the current element to see if it matches the selector, then its parent element, then its parent, etc. to the root of the tree. It returns the element it finds, or null if it doesn't find one.

For slightly older environments, Element#closest can be polyfilled. Or if you don't like polyfilling, you can give yourself a utility function instead that uses closest if it exists, or uses matches if not:

function closest(el, selector) {
    if (el.closest) {
        return el.closest(selector);
    }
    var matches = el.matches || el.matchesSelector;
    while (el) {
        if (matches.call(el, selector)) {
            return el;
        }
        el = el.parentNode;
    }
    return null;
}

...which you'd use like this:

if (closest(e, ".main-section")) {
    // One was found...
}

Upvotes: 5

Related Questions