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 findAll
name 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
How to Write Asynchronous Functions for Node.Js
How to Save a Leaflet Map with Drawn Shapes/Points on It in Shiny
How to See Ping Pong in Web Socket in iOS
How to Serialize Dom Node to JSON Even If There Are Circular References
Adding/Removing Items from a JavaScript Object with Jquery
Capture Browser Console Logs with Capybara
Setting a Variable to Get Return from Call Back Function Using Promise
Get Gps Location from the Web Browser
Template Language That Works on Both Server and Client
Dt: Link Binding Is Lost After Re-Rendering the Table
How to Use Source: Function()... and Ajax in Jquery UI Autocomplete
Safari Web Extension - Injecting Script Only When Extension Button Is Clicked
Rails 5 - Turbolinks 5,Some Js Not Loaded on Page Render
Detect Blocked Popup in Chrome
How to Programmatically Click on an Element in JavaScript