Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pure Javascript get parents

Tags:

javascript

I created a snippet based on .parents() without jquery - or querySelectorAll for parents

  function getParents (el, _class) {
    let doc = document
    let parents = []
    let p = el.parentNode

    while (p !== doc) {
      let o = p
      parents.push(o)
      p = o.parentNode
    }
    parents.push(doc)
    return parents[parents.map(x => x.className).indexOf(_class)]
  }

document.querySelectorAll('.child1').forEach((e,i)=>{
  console.log(getParents(e, 'child4'))
})
<div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            1
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


  <div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            2
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


  <div class="parent">
  <div class="child5">
    <div class="child4 hello">  <!-- problem here -->
      <div class="child3">
        <div class="child2">
          <div class="child1">
            3
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

if <div class="child4 hello"> without hello I can get all child4, if hello or anything else is added, I am unable to get child4. I use indexOf() I think shouldn't be -1 or undefined. Could someone please correct me where is the error? Thanks

like image 356
olo Avatar asked May 11 '26 07:05

olo


1 Answers

The problem is that you're getting a list of elements and you're mapping those to the elements' className, when the target element have more then just the child4 class, the value in the array will be child4 hello and when you're looking for the index of the child4 value in the array, the child4 hello won't match. Instead of Array.indexOf you can use Array.find.

  function getParents (el, _class) {
    let doc = document
    let parents = []
    let p = el.parentNode

    while (p !== doc) {
      let o = p
      parents.push(o)
      p = o.parentNode
    }
    parents.push(doc)
    return parents.find(e => e.className.includes(_class))
  }

document.querySelectorAll('.child1').forEach((e,i)=>{
  console.log(getParents(e, 'child4'))
})
<div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            1
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


  <div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            2
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


  <div class="parent">
  <div class="child5">
    <div class="child4 hello">  <!-- problem here -->
      <div class="child3">
        <div class="child2">
          <div class="child1">
            3
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Instead of the getParents function you could use Element.closest

Here is an example:

const parents = Array.from(document.querySelectorAll('.child1')).map(e => e.closest('.child4'));
console.log(parents);
<div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            1
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


<div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            2
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


<div class="parent">
  <div class="child5">
    <div class="child4 hello">
      <!-- problem here -->
      <div class="child3">
        <div class="child2">
          <div class="child1">
            3
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

As @Khauri mentioned, in the first example, instead of using the className property and using string functions to check if that value is a match, it will be better to use the classList property because it has a contains function.

like image 174
Titus Avatar answered May 13 '26 21:05

Titus



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!