Javascript get X parent node without jQuery

1.3k views Asked by At

I'm manually scraping data from some websites just using "Javascript:;" in a browser's address bar. It's easier than copy/pasting.

I've come across a few instances where I have to do: object.parentNode.parentNode.... to get some information and as it varies from site to site it could be at any level.

Obviously I don't want a loop and traverse it as that would make a simple task a bit more extensive.

Is there a way to do say: object.parentNode[4] or something such as without jQuery?

2

There are 2 answers

2
Cristi Mihai On

I don't think you'll manage to avoid a good ol' loop:

for(var i=0; i<4 && node.parentNode; node=node.parentNode, i++); alert(node);
0
ryanpcmcquen On

I wrote a function to do exactly this in Vanilla JavaScript:

https://github.com/ryanpcmcquen/queryparent

Here's the es5 version:

https://github.com/ryanpcmcquen/queryparent/blob/master/index-es5.js

Or if you only need to support modern browsers, you can use the es6 version:

https://github.com/ryanpcmcquen/queryparent/blob/master/index.js

You call it like so:

queryParent(SELECTOR, PARENT);

It will return the raw JavaScript node.

Here's a demo of it getting the exact class selector you would want, even though there is another element with the same selector (that you would not want):

https://jsfiddle.net/ryanpcmcquen/zkw0gdj7/

/*! queryParent.js v1.2.1 by ryanpcmcquen */
/*global module*/
/*jshint esversion:6*/

const d = document;
const qu = 'querySelector';

const queryParent = (s, p) => {
  const q = (x) => d[qu](x);
  const qa = (y) => d[`${qu}All`](y);
  const pa = qa(p);
  (typeof s === 'string') && (s = q(s));
  return [...pa].filter((n) => {
    return (n.contains(s)) ? n : false;
  }).pop();
};

//module.exports = queryParent;

console.log(
  queryParent('.bar', '.foo')
);

// PSST! Check the console!
<div>
  <ul class="foo">
    But there is also a <code>foo</code> we don't want here.
  </ul>
  <ul class="foo">
    The <code>foo</code> we want is here.
    <li>
      <ul>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul></ul>
        </li>
        <li>
          <ul class="bar"><code>bar</code> is here.</ul>
        </li>
      </ul>
    </li>
  </ul>
</div>

The reason I find this more useful, is that it does not rely on a certain number of .parent() calls (or conversely .parentNode in pure JS). For that reason it makes your code more future proof and less likely to stop working should the markup structure change.