How to find the nearest common ancestors of two or more nodes?

Viewed 17969

Users selects two or more elements in a HTML page. What i want to accomplish is to find those elements' common ancestors (so body node would be the common ancestor if none found before) ?

P.S: It can be achieved with XPath but it is not a preferable option for me. Also it may be found with css selector parsing but i think it is a dirty method (?)

Thank you.

15 Answers

based on the answers from Andy E and AntonB

handle edge-cases: node1 == node2 and node1.contains(node2)

function getCommonParentNode(node1, node2) {
  if (node1 == node2) return node1;
  var parent = node1;
  do if (parent.contains(node2)) return parent
  while (parent = parent.parentNode);
  return null;
}

Somewhat late to the party, here's a JavaScript ES6 version that uses Array.prototype.reduce() and Node.contains(), and can take any number of elements as parameters:

function closestCommonAncestor(...elements) {
    const reducer = (prev, current) => current.parentElement.contains(prev) ? current.parentElement : prev;
    return elements.reduce(reducer, elements[0]);
}

const element1 = document.getElementById('element1');
const element2 = document.getElementById('element2');
const commonAncestor = closestCommonAncestor(element1, element2);

PureJS

function getFirstCommonAncestor(nodeA, nodeB) {
    const parentsOfA = this.getParents(nodeA);
    const parentsOfB = this.getParents(nodeB);
    return parentsOfA.find((item) => parentsOfB.indexOf(item) !== -1);
}

function getParents(node) {
    const result = [];
    while (node = node.parentElement) {
        result.push(node);
    }
    return result;
}

did not liked any of the answers above(want pure javascript and one function). that worked perfectly for me,efficient and also easier to understand:

    const findCommonAncestor = (elem, elem2) => {
      let parent1 = elem.parentElement,parent2 = elem2.parentElement;
      let childrensOfParent1 = [],childrensOfParent2 = [];
      while (parent1 !== null && parent2 !== null) {
        if (parent1 !== !null) {
          childrensOfParent2.push(parent2);
          if (childrensOfParent2.includes(parent1)) return parent1;
        }
        if (parent2 !== !null) {
          childrensOfParent1.push(parent1);
          if (childrensOfParent1.includes(parent2)) return parent2;
        }
        parent1 = parent1.parentElement;
        parent2 = parent1.parentElement;
      }
      return null;
    };

Related