Using Queryselectorall to Retrieve Direct Children

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.

Get direct child with querySelectorAll

I think what you want is this:

const lang = document.querySelector('.lang');
const items = lang.querySelectorAll('li');

Now items will be all li inside .lang, that's how querySelectorAll works.

Read more on MDN

Why > li did not work? Because it's not a valid css selector

Why * > li works? Because it's a valid css selector. Moreover every li in any valid html code will always be inside ul or ol so technically; writing * > li is same as writing li

UPDATE :
For only first level li try this:

let lang = document.querySelector(".lang");let firstLevelLis =      Array.from(lang.querySelectorAll("li"))     .filter(node => node.parentNode === lang)
for(let li of firstLevelLis){ li.querySelector("span").style.backgroundColor = "red"}
<ul class="lang">  <li><span>Foo</span></li>  <li><span>Bar</span></li>  <li><span>Baz</span>    <ul>      <li><span>Don't make me red<span></li>      <li><span>Neither me</span></li>    </ul>  </li></ul>

querySelector search immediate children

Complete :scope polyfill

As avetisk has mentioned Selectors API 2 uses :scope pseudo-selector.

To make this work in all browsers (that support querySelector) here is the polyfill

(function(doc, proto) {
try { // check if browser supports :scope natively
doc.querySelector(':scope body');
} catch (err) { // polyfill native methods if it doesn't
['querySelector', 'querySelectorAll'].forEach(function(method) {
var nativ = proto[method];
proto[method] = function(selectors) {
if (/(^|,)\s*:scope/.test(selectors)) { // only if selectors contains :scope
var id = this.id; // remember current element id
this.id = 'ID_' + Date.now(); // assign new unique id
selectors = selectors.replace(/((^|,)\s*):scope/g, '$1#' + this.id); // replace :scope with #ID
var result = doc[method](selectors);
this.id = id; // restore previous id
return result;
} else {
return nativ.call(this, selectors); // use native code for other selectors
}
}
});
}
})(window.document, Element.prototype);

Usage

node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');

For historical reasons, my previous solution

Based on all answers

// Caution! Prototype extending
Node.prototype.find = function(selector) {
if (/(^\s*|,\s*)>/.test(selector)) {
if (!this.id) {
this.id = 'ID_' + new Date().getTime();
var removeId = true;
}
selector = selector.replace(/(^\s*|,\s*)>/g, '$1#' + this.id + ' >');
var result = document.querySelectorAll(selector);
if (removeId) {
this.id = null;
}
return result;
} else {
return this.querySelectorAll(selector);
}
};

Usage

elem.find('> a');

How to make a selector for direct child of the root node?

The proper way to do this is with the :scope psuedo class.

According to the documentation at MDN:

When used from a DOM API such as querySelector(), querySelectorAll(), matches(), or Element.closest(), :scope matches the element on which the method was called.

For example:

let parent = document.querySelector('#parent');
let scoped = parent.querySelectorAll(':scope > span');

Array.from(scoped).forEach(s => {
s.classList.add('selected');
});
.selected {
background: yellow;
}
<div id="parent">
<span> Select Me </span> <br>
<span> Me Too </span>
</div>
<span> Not Selected </span>

Get all child elements by className or querySelectorAll with Javascript

Use .divTest > * to select all elements which are immediate children of an element with a divTest class:

console.log(  document.querySelectorAll('.foo > *').length);
<div class="foo">  <div></div>  <div></div></div><div class="foo">  <div></div>  <div></div></div>

How to use querySelectorAll to get all children of a parent excluding only one child in javascript

I'm guessing that the .ignore-me element isn't a direct child of the .print div. So you'll want to remove the >, because that only excludes it if it's a direct child:

var theHtml=document.querySelectorAll(".print :not(.ignore-me)");

Example:

var theHtml=document.querySelectorAll(".print :not(.ignore-me)");console.log(`Length: ${theHtml.length}`);theHtml.forEach(el => {    const cls = el.className ? `.${el.className.replace(/ /g, ".")}` : "";    const id = el.id ? `#${el.id}` : "";    console.log(el.tagName + id + cls);});
<div>    <div class="print">        <div class="x">x</div>        <div class="y">            y            <div class="ignore-me">ignore</div>        </div>    </div></div>

How to target direct child from element

You are concatenating section.querySelector(section + "> div") a string with and object which is not work in querySelector
BTW if you use section.querySelector("div") it will return the first div of the elements so what you want is section.querySelectorAll("div")[2] which point to third div see the example in two parts, the second one is yours.

var section = document.getElementsByTagName("section")[0];var div = section.querySelector("div"); //this not work console.log(div);
//What you wantvar section = document.getElementsByTagName("section")[0];var div = section.querySelectorAll("div"); //this not workvar target = div[2];console.log(target);
<section>  <form>    <div>1</div>    <div>2</div>  </form>  <div> I want target this div    <div>3</div>    <div>4</div>  </div></section>

When using querySelectorAll, is there a way to reference the immediate children of the context node, without using IDs?

No, there isn't a way (yet) to reference all childs of some element without using a reference to that element. Because > is a child combinator, which represents a relationship between a parent and child element, a simple selector (a parent) is necessary (which is missing in you example).

In a comment, BoltClock said that the Selectors API Level 2 specification defines a method findAllname may change "which accepts as an argument what will probably be known as a relative selector (a selector that can start with a combinator rather than a compound selector)".

When this is implemented, it can be used as follows:

a_div.findAll('> div');

How to get the first level child element of a DOM element retrieved by document.getElementById in JavaScript?

If outer is already in a variable, you can use :scope at the start of a query string with querySelectorAll to "select" the element the querySelectorAll is being called on:

var outer = document.getElementById("outer");outer.querySelectorAll(":scope > .inner").forEach((e) => {  e.style.border = "1px solid red";});
<div id="outer">  <div class="inner">inner</div>  <div id="test">    <div class="inner">inner2</div>  </div></div>


Related Topics



Leave a reply



Submit