Using querySelectorAll to retrieve direct children
I am able to do this:
<div id="myDiv">
<div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");
That is, I can successfully retrieve all the direct children of the myDiv
element that have class .foo
.
The problem is, it bothers me that I must include the #myDiv
in the selector, because I am running the query on the myDiv
element (so it is obviously redundant).
I ought to be able to leave the #myDiv
off, but then the selector is not legal syntax since it starts with a >
.
Does anyone know how to write a selector which gets just the direct children of the element that the selector is running on?
Solution 1:
Good question. At the time it was asked, a universally-implemented way to do "combinator rooted queries" (as John Resig called them) did not exist.
Now the :scope pseudo-class has been introduced. It is not supported on [pre-Chrominum] versions of Edge or IE, but has been supported by Safari for a few years already. Using that, your code could become:
let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");
Note that in some cases you can also skip .querySelectorAll
and use other good old-fashioned DOM API features. For example, instead of myDiv.querySelectorAll(":scope > *")
you could just write myDiv.children
, for example.
Otherwise if you can't yet rely on :scope
, I can't think of another way to handle your situation without adding more custom filter logic (e.g. find myDiv.getElementsByClassName("foo")
whose .parentNode === myDiv
), and obviously not ideal if you're trying to support one code path that really just wants to take an arbitrary selector string as input and a list of matches as output! But if like me you ended up asking this question simply because you got stuck thinking "all you had was a hammer" don't forget there are a variety of other tools the DOM offers too.
Solution 2:
Does anyone know how to write a selector which gets just the direct children of the element that the selector is running on?
The correct way to write a selector that is "rooted" to the current element is to use :scope
.
var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");
However, browser support is limited and you'll need a shim if you want to use it. I built scopedQuerySelectorShim for this purpose.