1

Here is my sample HTML:

<div id="parent1" data-attribute="parent">
  <div id="child2" data-attribute="child">
    <div id="grandchild4" data-attribute="child">
    </div>
  </div>
</div>
<div id="parent2" data-attribute="parent">
  <div id="child3" data-attribute="child">
    <div id="grandchild1" data-attribute="parent">
      <div id="item1"></div>
    </div>
  </div>
  <div id="child4" data-attribute="parent">
    <div id="grandchild2" data-attribute="child">
      <div id="grandchild3" data-attribute="parent">
        <div id="item2" data-attribute="child">
          <div id="sub1" data-attribute="child">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

If the current element I'm performing query selection on is sub1, how do I find the last ancestor with data-attribute="parent"? In this case, the expected result should be parent2.

I know closest() will return the first match which would be grandchild3, but is there like a selector to find the final ancestor? Querying by id is not option, since my id's are dynamically created.

mark uy
  • 391
  • 4
  • 14

4 Answers4

0

First, to find all the ancestors, you can combine two conditions [data-attribute="parent"] and [id^="parent"]. More on wildcard selectors

$('div[id^="parent"][data-attribute="parent"]')

Now, once you have all the ancestors, the last() should give you the immediate one. Please find the snippet below

console.log($('div[id^="parent"][data-attribute="parent"]').last().attr('id'))
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>

<div id="parent1" data-attribute="parent">
  <div id="child2" data-attribute="child">
    <div id="grandchild4" data-attribute="child">
      grandchild4
    </div>
  </div>
</div>
<div id="parent2" data-attribute="parent">
  <div id="child3" data-attribute="child">
    <div id="grandchild1" data-attribute="parent">
      grandchild1
      <div id="item1">item1</div>
    </div>
  </div>
  <div id="child4" data-attribute="parent">
    <div id="grandchild2" data-attribute="child">
      <div id="grandchild3" data-attribute="parent">
        grandchild3
        <div id="item2" data-attribute="child">
          item2
          <div id="sub1" data-attribute="child">
            sub1
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Nidhin Joseph
  • 8,658
  • 3
  • 18
  • 40
0

You can create your own version of closest which will give you the last ancestor of the type you require. If you're using jQuery:

$.fn.extend({
  closestTop: function(selection) {
    var el = this;
    var lastKnown = null;
    do {
      lastKnown = el;
      var guess = $(el).parent().length && $(el).parent().closest(selection || '');
      el = guess && guess.length && guess.get(0) || null;
    } while (el != null);
    return $(lastKnown);
  }
});

console.log($('#sub1').closestTop('[data-attribute=parent]'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="parent1" data-attribute="parent">
  <div id="child2" data-attribute="child">
    <div id="grandchild4" data-attribute="child">
    </div>
  </div>
</div>
<div id="parent2" data-attribute="parent">
  <div id="child3" data-attribute="child">
    <div id="grandchild1" data-attribute="parent">
      <div id="item1"></div>
    </div>
  </div>
  <div id="child4" data-attribute="parent">
    <div id="grandchild2" data-attribute="child">
      <div id="grandchild3" data-attribute="parent">
        <div id="item2" data-attribute="child">
          <div id="sub1" data-attribute="child">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Inkling
  • 2,656
  • 3
  • 24
  • 38
joyBlanks
  • 5,894
  • 1
  • 15
  • 42
0

You could write an XPath expression and evaluate that.

const element = document.querySelector('#sub1');
const xpath = 'ancestor::*[@data-attribute="parent"][last()]';
const result = document.evaluate(xpath, element, null, 
                   XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;

console.log(result);
<div id="parent1" data-attribute="parent">
  <div id="child2" data-attribute="child">
    <div id="grandchild4" data-attribute="child">
    </div>
  </div>
</div>
<div id="parent2" data-attribute="parent">
  <div id="child3" data-attribute="child">
    <div id="grandchild1" data-attribute="parent">
      <div id="item1"></div>
    </div>
  </div>
  <div id="child4" data-attribute="parent">
    <div id="grandchild2" data-attribute="child">
      <div id="grandchild3" data-attribute="parent">
        <div id="item2" data-attribute="child">
          <div id="sub1" data-attribute="child">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Robby Cornelissen
  • 72,308
  • 17
  • 104
  • 121
0

It' right???

document.getElementById("sub1").addEventListener("click", function(){

  let ancester = this.parentElement;
  let flag = ancester.getAttribute("data-attribute");

  while(flag !== "parent") {
    ancester = ancester.parentElement;
    flag = ancester.getAttribute("data-attribute");
  }

  console.log(ancester);
});