rsk82
rsk82

Reputation: 29407

how to get all parent nodes of given element in pure javascript?

I mean an array of them. That is a chain from top HTML to destination element including the element itself.

for example for element <A> it would be:

[HTML, BODY, DIV, DIV, P, SPAN, A]

Upvotes: 42

Views: 57170

Answers (7)

Nathan
Nathan

Reputation: 11159

You can walk the chain of element.parentNodes until you reach an falsey value, appending to an array as you go:

const getParents = el => {
  for (var parents = []; el; el = el.parentNode) {
    parents.push(el);
  }

  return parents;
};

const el = document.querySelector("b");
console.log(getParents(el).reverse().map(e => e.nodeName));
<div><p><span><b>Foo</b></span></div>

Note that reversing is done in the caller because it's not essential to the lineage algorithm. Mapping to e.nodeName is purely for presentation and also non-essential.

Note that this approach means you'll wind up with the document element as the last element in the chain. If you don't want that, you can add && el !== document to the loop stopping condition.

The overall time complexity of the code above is linear and reverse() is in-place, so it doesn't require an extra allocation. unshift in a loop, as some of the other answers recommend, is quadratic and may harm scalability on uncommonly-deep DOM trees in exchange for a negligible gain in elegance.

Upvotes: 5

MD SHAYON
MD SHAYON

Reputation: 8063

get all parent nodes of child in javascript array

let selectedTxtElement = document.getElementById("target");
    let els = [];
    while (selectedTxtElement) {
         els.unshift(selectedTxtElement);
         selectedTxtElement = selectedTxtElement.parentNode;
    }

know more

Upvotes: -2

Yury Ershov
Yury Ershov

Reputation: 424

I like this method:

[...(function*(e){do { yield e; } while (e = e.parentNode);})($0)]

... where $0 is your element.

An upside of this method is that it can be used as a value in expressions.

To get an array without the target element:

[...(function*(e){while (e = e.parentNode) { yield e; }})($0)]

Upvotes: 10

Alex Sz&#252;cs
Alex Sz&#252;cs

Reputation: 681

Another alternative (based on this):

for(var e = document.getElementById("target"),p = [];e && e !== document;e = e.parentNode)
p.push(e);

Upvotes: 2

Jack G
Jack G

Reputation: 5341

I believe this will likely be the most performant in the long run in the most scenarios if you are making frequent usage of this function. The reason for why t will be more performant is because it initially checks to see what kind of depths of ancestry it might encounter. Also, instead of creating a new array every time you call it, this function will instead efficiently reuse the same array, and slice it which is very optimized in some browsers. However, since there is no really efficient way I know of to check the maximum depth, I am left with a less efficient query-selector check.

// !IMPORTANT! When moving this coding snippet over to your production code,
// do not run the following depthtest more than once, it is not very performant
var kCurSelector="*|*", curDepth=3;
while (document.body.querySelector(kCurSelector += '>*|*')) curDepth++;
curDepth = Math.pow(2, Math.ceil(Math.log2(startDepth))),
var parentsTMP = new Array(curDepth);

function getAllParentNodes(Ele){
    var curPos = curDepth;

    if (Ele instanceof Node)
      while (Ele !== document){
        if (curPos === 0){
          curPos += curDepth;
          parentsTMP.length <<= 1;
          parentsTMP.copyWithin(curDepth, 0, curDepth);
          curDepth <<= 1;
        }
        parentsTMP[--curPos] = Ele;
        Ele = Ele.parentNode;
      }
    return retArray.slice(curPos)
}

The browser compatibility for the above function is that it will work in Edge, but not in IE. If you want IE support, then you will need a Array.prototype.copyWithin polyfill.

Upvotes: 0

techfoobar
techfoobar

Reputation: 66693

You can try something like:

var nodes = [];
var element = document.getElementById('yourelement');
nodes.push(element);
while(element.parentNode) {
    nodes.unshift(element.parentNode);
    element = element.parentNode;
}

Upvotes: 26

Wayne
Wayne

Reputation: 60424

A little shorter (and safer, since target may not be found):

var a = document.getElementById("target");
var els = [];
while (a) {
    els.unshift(a);
    a = a.parentNode;
}

Upvotes: 67

Related Questions