0

Given html:

<div data-root="A">
 <div>Ignored</div>
 <div data-child="B">
  <div data-child="C" data-root="E">
    <div data-child="F"></div>
    <div data-child="G">
     <div data-root="Q">
      <div data-child="K"></div>
     </div>
    </div>
  </div>
 </div>
</div>

For any given element (root) I want to query all child elements having data-child attribute populated and not owned by another element with data-root specified.

Sample outcomes:

  • Data Root A: Data children: B, C
  • Data Root E: Data children: F, G, Q
  • Data Root Q: Data children: K

I solved it by calling root.querySelectorAll("[data-child]") and then checking each element individually by tracing it up to the parent while checking if any elements by the way have data-root specified. It works, but the code is a bit awkward for what it's doing. Ideally I'm looking for a codeless declarative solution, can anyone come up with it for my problem?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Simple.Js
  • 91
  • 6

2 Answers2

1

The only selector-based solution available, in the form

root.querySelectorAll("[data-child]:not(:scope [data-root] *)")

makes use of Selectors level 4 features that are not yet supported by all browsers and so probably won't work for your needs. There is no such solution available in Selectors level 3.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • fair enough. I'll give it a try. How do I test for the support of Level 4 in Js to create a fallback? – Simple.Js Jun 22 '18 at 08:55
  • @Simple.Js: I missed your previous comment. You can test this by putting this selector in a try {} and the fallback in a catch {}. No idea when Chrome is planning to support it unfortunately. – BoltClock Jul 17 '18 at 10:10
0

Another not so well supported way to this would be to use Element method closest with the relevant selector.

Simple.Js
  • 91
  • 6