Using querySelectorAll(). Is the result returned by the method ordered?
The returned node list is ordered. A quick test proved it:
document.querySelectorAll("body, head")[0]; //Returned [object HTMLHeadElement]
Obviously, the <head>
tag appears before <body>
in a HTML document. The first element of the NodeList is also a <head>
element, even if the selector shows body
before `head.
From http://www.w3.org/TR/selectors-api/#queryselectorall:
The
querySelectorAll()
method on the NodeSelector interface must, when
invoked, return a NodeList containing all of the matching Element
nodes within the node’s subtrees, in document order. If there are no
such nodes, the method must return an empty NodeList.
Javascript querySelectorAll('*') return format
'elems' will be a non-live NodeList of element objects. Traversal will be DFS (depth first search)
docs
What type of data does querySelectorAll return?
The Element method
querySelectorAll()
returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
For the differences please visit: Difference between HTMLCollection, NodeLists, and arrays of objects
You can use Spread syntax to make that as an array:
var obj1 = { fname: "Mirajul", lname: "Momin", age: 24};console.log(obj1.length);var paraList = [...document.querySelectorAll("p")];console.log(paraList.length);console.log(Array.isArray(paraList));
<p>This is paragraph one</p><p>This is paragraph two</p><p>This is paragraph three</p><p>This is paragraph four</p>
What do querySelectorAll and getElementsBy* methods return?
Your getElementById
code works since IDs have to be unique and thus the function always returns exactly one element (or null
if none was found).
However, the methodsgetElementsByClassName
,getElementsByName
,getElementsByTagName
, andgetElementsByTagNameNS
return an iterable collection of elements.
The method names provide the hint: getElement
implies singular, whereas getElements
implies plural.
The method querySelector
also returns a single element, and querySelectorAll
returns an iterable collection.
The iterable collection can either be a NodeList
or an HTMLCollection
.
getElementsByName
and querySelectorAll
are both specified to return a NodeList
; the other getElementsBy*
methods are specified to return an HTMLCollection
, but please note that some browser versions implement this differently.
Both of these collection types don’t offer the same properties that Elements, Nodes, or similar types offer; that’s why reading style
off of document.getElements
…(
…)
fails.
In other words: a NodeList
or an HTMLCollection
doesn’t have a style
; only an Element
has a style
.
These “array-like” collections are lists that contain zero or more elements, which you need to iterate over, in order to access them.
While you can iterate over them similarly to an array, note that they are different from Array
s.
In modern browsers, you can convert these iterables to a proper Array with Array.from
; then you can use forEach
and other Array methods, e.g. iteration methods:
Array.from(document.getElementsByClassName("myElement"))
.forEach((element) => element.style.size = "100px");
In old browsers that don’t support Array.from
or the iteration methods, you can still use Array.prototype.slice.call
.
Then you can iterate over it like you would with a real array:
var elements = Array.prototype.slice
.call(document.getElementsByClassName("myElement"));
for(var i = 0; i < elements.length; ++i){
elements[i].style.size = "100px";
}
You can also iterate over the NodeList
or HTMLCollection
itself, but be aware that in most circumstances, these collections are live (MDN docs, DOM spec), i.e. they are updated as the DOM changes.
So if you insert or remove elements as you loop, make sure to not accidentally skip over some elements or create an infinite loop.
MDN documentation should always note if a method returns a live collection or a static one.
For example, a NodeList
offers some iteration methods such as forEach
in modern browsers:
document.querySelectorAll(".myElement")
.forEach((element) => element.style.size = "100px");
A simple for
loop can also be used:
var elements = document.getElementsByClassName("myElement");
for(var i = 0; i < elements.length; ++i){
elements[i].style.size = "100px";
}
Aside: .childNodes
yields a live NodeList
and .children
yields a live HTMLCollection
, so these two getters also need to be handled carefully.
There are some libraries like jQuery which make DOM querying a bit shorter and create a layer of abstraction over “one element” and “a collection of elements”:
$(".myElement").css("size", "100px");
JavaScript why cannot select the elements
According to mdn:
The Document method querySelectorAll() returns a static (not live)
NodeList representing a list of the document's elements that match the
specified group of selectors.
It is like the document.getElementsByClassName
which return you a nodelist and you have to specify the index or you could use document.querySelector
const content = document.querySelectorAll('.test');
content[0].classList.add('hide-content');
.Content {
width: 180px;
height: 90px;
background-color: green;
}
.hide-content {
display: none
}
<div class="Content"></div>
<div class="Content test"></div>
<div class="Content test"></div>
Is order of resulting array of document.querySelectorAll(input[type=checkbox) guaranteed?
1
Yes, the order is guaranteed.
The specification states
The
querySelectorAll()
methods on the Document, DocumentFragment, and
Element interfaces must return a NodeList containing all of the
matching Element nodes within the subtrees of the context node, in
document order. If there are no matching nodes, the method must return
an empty NodeList.
meaning the elements will be returned in the order they appear in the document
2
If checkboxes are added, the best way to get those elements would be to keep track of them when inserting.
Other than that, wrapping them in another element with an ID or class would work as well, or just giving the new checkboxes a class
var new_boxes = document.querySelectorAll('.new_boxes');
3
Generally you'd just submit the form, and the checked boxes will be sent automatically.
If you're sending the data with ajax, you can get the checked boxes with an attribute selector
var boxes = document.querySelector('input[type="checkbox"][checked]');
How do I parse the results of a querySelectorAll selector engine & allow method chaining?
I want to use it like this...:
$("div").innerHTML='It works!';
...not like this...:
$("div")[0].innerHTML='It works only on the specified index!';
It sounds like you want to have assigning to innerHTML
on your set of results assign to the innerHTML
of all of the results.
To do that, you'll have to use a function, either directly or indirectly.
Directly:
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(),
node = node || document.body,
rv;
if (selector != null) {
rv = Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
rv.setInnerHTML = setInnerHTML;
}
return rv;
}
function setInnerHTML(html) {
var index;
for (index = 0; index < this.length; ++index) {
this[index].innerHTML = html;
}
}
// Usage
$("div").setInnerHTML("The new HTML");
There, we define a function, and we assign it to the array you're returning as a property. You can then call that function on the array. (You might want to use Object.defineProperty
if it's available to set the setInnerHTML
property, so you can make it non-enumerable.)
Indirectly (requires an ES5-enabled JavaScript engine):
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(),
node = node || document.body,
rv;
if (selector != null) {
rv = Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
Object.defineProperty(rv, "innerHTML", {
set: setInnerHTML
});
}
return rv;
}
function setInnerHTML(html) {
var index;
for (index = 0; index < this.length; ++index) {
this[index].innerHTML = html;
}
}
// Usage
$("div").innerHTML = "The new HTML";
There, we use Object.defineProperty
to define a setter for the property.
In the comments below you say
I have a few prototypes that work when individually attached to the $ function. Example:
$('div').makeClass('this');
They do not work when they are chained together. Example:$('div').makeClass('this').takeClass('that');
To make chaining work, you do return this;
from each of the functions (so the end of makeClass
would do return this;
). That's because when you're chaining, such as obj.foo().bar()
, you're calling bar
on the return value of foo
. So to make chaining work, you make sure foo
returns this
(the object on which foo
was called).
Related Topics
JavaScript Change Background Color on Click
How Does Github Change the Url But Not the Reload
How to Detect Overflow in Div Element
Center an Image Vertically and Horizontally Using CSS
Jquery to Change Style Attribute of a Div Class
Using JavaScript to Detect Google Chrome to Switch CSS
Mutationobserver: New Value in the Format of 'Oldvalue'
How to Use .Env Variables in Nuxt 2 or 3
Why am I Seeing an "Origin Is Not Allowed by Access-Control-Allow-Origin" Error Here
Chrome Extension Code VS Content Scripts VS Injected Scripts
HTML Mobile -Forcing the Soft Keyboard to Hide
How to Change the Background Image of Div Using JavaScript
Getelementsbyclassname to Change the Style of Elements When Event Occurs
Converting Em to Px in JavaScript (And Getting Default Font Size)
Programmatically Editing Less (Css) Code with Jquery-Like Selector Syntax