6

Apologies for this kind of question, but I can't find an answer on You Might Not Need jQuery or anywhere else online and I'd really like to know:

What is the pure JavaScript equivalent of jQuery's .parents() method?

For example, it would be great to know how to do this in pure JavaScript:

jQuery(element).parents('.className');
user5508297
  • 805
  • 2
  • 9
  • 24
  • 2
    *"What is the pure JavaScript equivalent of jQuery's .parents() method?"* There is none. Do you mean "What's the DOM API version of jQuery's `parents()` method?" – T.J. Crowder Jul 19 '16 at 22:58
  • 8
    `while ((element = element.parentElement)) { if (element.matches('.className')) { result.push(element) } }` –  Jul 19 '16 at 22:59
  • I was pretty sure this is a duplicate but I can't find it. – Bergi Jul 19 '16 at 23:08
  • 2
    You can always look at jQuery's github for their source: [.parents()](https://github.com/jquery/jquery/blob/305f193aa57014dc7d8fa0739a3fefd47166cd44/src/traversing.js#L115) -> [dir()](https://github.com/jquery/jquery/blob/master/src/traversing/var/dir.js) – Patrick Evans Jul 19 '16 at 23:10
  • Ah, yes [this](http://stackoverflow.com/q/12980877/1048572) is what I was looking for – Bergi Jul 19 '16 at 23:14
  • I went straight to their github and searched, but it seems "bitten" did have an answer below that also listed the transversing module – Patrick Evans Jul 19 '16 at 23:21

2 Answers2

8

There is no one function/property in the DOM API that equates to jQuery's parents(). There is the parentNode property (and as Oriol points out, the parentElement property, which will prevent your going from document.documentElement up to document), which is the parent node (or parent element) of the element on which you access it, or null if it doesn't have one. To roughly match jQuery's parents(), you can loop on it (e.g., get the parentNode/parentElement of the parentNode/parentElement, etc.) to find all the parents. As squint notes, on vaguely-modern browsers at each level you can use matches to check if the parent matches a selector (to match jQuery's behavior with parents() when you pass it a selector).

jQuery takes a set-based approach to DOM manipulation and traversal, whereas the DOM API takes a per-element/node approach.

Example:

var elm = document.getElementById("target");
var parents = getParents(elm);
console.log(Array.prototype.map.call(
  parents,
  function(e) {
    return e.nodeName + (e.id ? "#" + e.id : "");
  }
).join(", "));
function getParents(e) {
  var result = [];
  for (var p = e && e.parentElement; p; p = p.parentElement) {
    result.push(p);
  }
  return result;
}
<div id="outermost">
  <div id="middle">
    <div id="inner">
      <div id="target"></div>
    </div>
  </div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    Use `parentElement` instead of `parentNode` to avoid `document`. – Oriol Jul 19 '16 at 23:08
  • @Oriol: That requires more modern browsers than `matches`/`matchesSelector` though – Bergi Jul 19 '16 at 23:11
  • @Bergi Maybe, if you consider non-standard names with vendor prefixes. `parentElement` doesn't need that, and has much more support than `matches`. – Oriol Jul 19 '16 at 23:17
  • 1
    @Oriol: Ooops, right, I mixed `matchesSelector` with `matches` support. – Bergi Jul 19 '16 at 23:21
2

Node.parentNode

When you get a HTML via some method (document.getElementById(), document.querySelector(), etc) it will return a Node object, the .parentNode property of the object is the parent Node object


To get all parent nodes, akin to jQuery's .parents():

I wrote this function a while back:

function parents(node) {
   let current = node,
       list    = [];
   while(current.parentNode != null && current.parentNode != document.documentElement) {
     list.push(current.parentNode);
     current = current.parentNode;
   }
    return list
}

Please note this is only slightly tested, so take it with a grain of salt

bren
  • 4,176
  • 3
  • 28
  • 43