querySelector with more than 2 conditions is not working

I have a code sample that basically tries to get the link i.e. a element within a li element using querySelector with 4 OR conditions. The sample is at QuerySelector sample.

The problem is that when I use 4 OR conditions then I get nothing returned for clickedLink1, but when I use only the last 2 OR conditions then I get a valid link returned for clickedLin2.

This appears strange to me unless I am committing some silly mistake. I looked up the docs at element.querySelector and I couldn’t find anything that will make my sample behave in this manner.

Question

Why is the clickedLink1 variable null even though its last 2 selectors are returning a valid link as is evident from the value of clickedLink2 variable?

The same sample code is given below for reference sake.

<script>
    window.onload = function() {
        let clickedLi = document.getElementById("div1").querySelector("li");
        let clickedLink1 = clickedLi.querySelector("[href*='/profile/']", "[href*='/account/']", "[href^='https://']", "[href^='http://']");
        if (clickedLink1) {
            alert(clickedLink1.outerHTML);
        } else {
            alert("clickedLink1 is null");
        }

        let clickedLink2 = clickedLi.querySelector("[href^='https://']", "[href^='http://']");
        if (clickedLink2) {
            alert("clickedLink2 is NOT null");
            alert(clickedLink2.outerHTML);
        } else {
            alert("clickedLink2 is undefined or null");
        }
    }
</script>
<div id="div1">
    <li id="comp-j52lnuvk1" data-direction="ltr" data-listposition="center" data-data-id="dataItem-l5djjzu1" data-state="menu false  link" data-index="1" class="S29as _3PptM" data-original-gap-between-text-and-btn="11" aria-hidden="false" style="width: 117px; height: 118px; position: relative; box-sizing: border-box; overflow: visible; visibility: inherit;">
        <a data-testid="linkElement" href="https://www.example.com/plans-pricing" target="_self" class="_1yi_g" aria-haspopup="false">
            <div class="_39-mO">
                <div class="" style="text-align:left">
                    <p class="_1NCeO" style="text-align: left; line-height: 118px;" id="comp-j52lnuvk1label">
                        Plans &amp; Pricing
                    </p>
                </div>
            </div>
        </a>
    </li>
</div>

>Solution :

querySelector only accepts one argument, a string defining a selector; it ignores any other arguments. So your first call:

let clickedLink1 = clickedLi.querySelector("[href*='/profile/']", "[href*='/account/']", "[href^='https://']", "[href^='http://']");

is treated like:

let clickedLink1 = clickedLi.querySelector("[href*='/profile/']");

It only looks for matches for the selector [href*='/profile/'] (ignoring the ones defined by the other strings).

The same is true for your second call, but it looks for [href^='https://'] instead. So your second call will find elements that match [href^='https://'], but the first one won’t because that selector is the third argument in the first call, which is ignored.

The single selector string you pass in can contain a selector group (one with commas), but it all has to be in one string. So:

let clickedLink1 = clickedLi.querySelector("[href*='/profile/'], [href*='/account/'], [href^='https://'], [href^='http://']");
// ...
let clickedLink2 = clickedLi.querySelector("[href^='https://'], [href^='http://']");

Notice that I’ve removed all the inner ", just keeping the one at the very beginning and the one at the very end.

Each of those will return the first element, in document order, that matches any of the href attribute selectors in the string passed in. (If you want all matching elements instead, use querySelectorAll instead to get a NodeList.)

Leave a Reply