Using querySelectorAll to retrieve direct children
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.
if you know for sure the element is unique (such as your case with the ID):
myDiv.parentElement.querySelectorAll("#myDiv > .foo");
For a more "global" solution: (use a matchesSelector shim)
function getDirectChildren(elm, sel){
var ret = [], i = 0, l = elm.childNodes.length;
for (var i; i < l; ++i){
if (elm.childNodes[i].matchesSelector(sel)){
ret.push(elm.childNodes[i]);
}
}
return ret;
}
where elm
is your parent element, and sel
is your selector. Could totally be used as a prototype as well.
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.