3

I use webdriver and often work with css selector and wondering if the amount of code I write to traverse each level can be decreased. Following is the javascript code to access an element and similar code in java would be present in my code.

in the below example I used 3 css selectors to traverse 3 levels and can I combine them together or atleast simplify.

document.querySelector('.datagrid').querySelectorAll(".even")[3].querySelectorAll('tbody tr')
1

2 Answers 2

7

You can use descendant or child selectors (technically "combinators") to combine the first part:

document.querySelectorAll('.datagrid .even')[3].querySelectorAll('tbody tr')

...but it will make the browser work a bit harder than your code does, because the first part of your code (document.querySelector('.datagrid')) will stop looking when it finds the first matching element, and then look for .even elements only within that. The above looks for all .even elements that have .datagrid ancestors. So it may need to search more of the document. Most of the time that doesn't matter, but it's worth pointing out. The above also assumes that there are at least four .even elements in the first .datagrid. If there aren't, your code would throw an error (because of the attempt to call .querySelectorAll on [3], which would be null), whereas the above code might throw an error (if there aren't four in total on the page), or might refer to an .even element in a subsequent .datagrid rather than the first.

The [3] makes it tricky to combine that with the one that follows. It's tempting to use .even:nth-child(3) or .even:nth-of-type(3), but that would be a mistake, because neither of those counts matches for .even and then takes the third one. nth-child matches only elements that are both .even and the third child element of their parent (considering all elements, not just .even ones). nth-of-type does the same thing, but only considering other elements that have the same tag. If you have other non-.even elements with the same tag name, it will be wrong.

Sometimes you hear talk about adding a selector (similar to the :eq provided by jQuery) to do what you're talking about, but the problem (as I understand it) is it would require a fundamental change to how selector engines process selectors (which is right-to-left). (There's also the problem that jQuery is incredibly widely used, and uses 0 as the first element's index, whereas CSS uses 1 in similar situations. So CSS would have to use something other than :eq — perhaps :index? — to avoid confusion.)

Sign up to request clarification or add additional context in comments.

5 Comments

I would +1 this for each paragraph if I could :)
Two things I question about your answer. First, as I understand it, querySelector('.datagrid') only gets the first .datagrid element, whereas your combined querySelectorAll('.datagrid .even') would pull from all .datagrid elements. Second, if there are nested .even elements (so .even is parent to other .even elements), would the OP's version and your combined version return those elements in the same order such that the [3] element was in fact the same for both sets of returned values?
@ScottS: Oddly, I don't seem to have got a notification of your comment. Excellent observations. It's absolutely true that the above will consider .even elements within more than just the first .datagrid, I've updated the answer to explain that. The order of the matched .even elements will be unchanged, though; both the OP's code and the above will give the .even elements in document order, nested or not. But the above also behaves differently if there are multiple .datagrid elements and the first doesn't have four .even elements in it, so I've flagged that up again. Thanks!
@ScottS: In answer to your second question, the spec says it must always return elements in document order. What "document order" exactly refers to is defined here: w3.org/TR/selectors-api/#the-apis which also covers nested elements.
@BoltClock and T.J. Crowder: Thank you both for the clarifications on "document order," especially the spec link with its notation about "depth-first pre-order traversal."
0

Pretty much anything you can do with a css selector you can do with querySelector(), so if you know your css selectors, you should be ok.

"The string argument pass to querySelector must follow the CSS syntax" - extract from the API.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.