'About querySelector() with multiple selectors
I had a situation in which I wanted to focus either an input tag, if it existed, or it's container if it didn't. So I thought of an intelligent way of doing it:
document.querySelector('.container input, .container').focus();
Funny, though, querySelector
always returns the .container
element.
I started to investigate and came out that, no matter the order in which the different selectors are put, querySelector
always returns the same element.
For example:
var elem1 = document.querySelector('p, div, pre');
var elem2 = document.querySelector('pre, div, p');
elem1 === elem2; // true
elem1.tagName; // "P".
My question is: What are the "reasons" of this behavior and what "rules" (if any) make P elements have priority over DIV and PRE elements.
Note: In the situation mentioned above, I came out with a less-elegant but functional solution:
(document.querySelector('.container input') || document.querySelector('.container') ).focus();
Solution 1:[1]
document.querySelector
returns only the first element matched, starting from the first element in the markup. As written on MDN:
Returns the first element within the document (using depth-first pre-order traversal of the document's nodes|by first element in document markup and iterating through sequential nodes by order of amount of child nodes) that matches the specified group of selectors.
If you want all elements to match the query, use document.querySelectorAll
(docs), i.e. document.querySelectorAll('pre, div, p')
. This returns an array of the matched elements.
Solution 2:[2]
The official document says that,
Returns the first element within the document (using depth-first pre-order traversal of the document's nodes|by first element in document markup and iterating through sequential nodes by order of amount of child nodes) that matches the specified group of selectors.
So that means, in your first case .container
is the parent element so that it would be matched first and returned. And in your second case, the paragraph should be the first element in the document while comparing with the other pre
and div
. So it was returned.
Solution 3:[3]
That's precisely the intended behavior of .querySelector()
— it finds all the elements in the document that match your query, and then returns the first one.
That's not "the first one you listed", it's "the first one in the document".
This works, essentially, like a CSS selector. The selectors p, div, pre
and pre, div, p
are identical; they both match three different types of element. So the reason elem1.tagName == 'P'
is simply that you have a <p>
on the page before any <pre>
or <div>
tags.
Solution 4:[4]
You can try selecting all elements with document.querySelectorAll("p.a, p.b") as shown in the example below and using a loop to focus on all elements that are found.
<html>
<body>
<p class="a">element 1</p>
<p class="b">element 2</p>
<script>
var list=document.querySelectorAll("p.a, p.b");
for (let i = 0; i < list.length; i++) {
list[i].style.backgroundColor = "red";
}
</script>
</body>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Thijs Kramer |
Solution 2 | Rajaprabhu Aravindasamy |
Solution 3 | VoteyDisciple |
Solution 4 | Frida |