One of the most essential skills in our web development toolbox is finding elements in the DOM. We need the help of a couple methods to make the process quick and easy.
- Use document.querySelectorAll to find nested nodes
- Change the value of the correct DOM nodes
To practice finding elements in the DOM, we're going to make use of two methods
that are useful for navigating the DOM: querySelector()
and
querySelectorAll()
.
querySelector()
takes one argument, a string of selectors, and
returns the first element that matches these selectors. Given a document like
<body>
<div>
Hello!
</div>
<div>
Goodbye!
</div>
</body>
If we called document.querySelector('div')
, the method would return the first
div
(whose content is "Hello!").
Selectors aren't limited to tag names, though (otherwise why not just use document.getElementsByTagName('div')[0]
?). We can get very fancy.
<body>
<div>
<ul class="ranked-list">
<li>1</li>
<li>
<div>
<ul>
<li>2</li>
</ul>
</div>
</li>
<li>3</li>
</ul>
</div>
<div>
<ul class="unranked-list">
<li>6</li>
<li>2</li>
<li>
<div>4</div>
</li>
</ul>
</div>
<script>
// get <li>2</li>
const li2 = document.querySelector('ul.ranked-list li ul li')
// get <div>4</div>
const div4 = document.querySelector('ul.unranked-list li div')
</script>
</body>
In the above example, the first query says, "Starting from document
(the
object we've called querySelector()
on), find a ul
with a className
of
ranked-list
(the .
is for className
). Then find an li
that is a child of
that ul
. Then find a ul
that is a child (but not necessarily a direct
descendant) of that li
. Finally, find an li
that is a child of that (second)
ul
."
NOTE: The HTML property class
is referred to as className
in JavaScript.
It's... unfortunate.
What, then, does the second call to querySelector()
say? Puzzle it out for a
bit, and then read on.
Puzzle a bit longer!
Just a bit longer!
Okay, the second call says, "Starting from document
, find a ul
with a
className
of unranked-list
. Then find an li
descended from
ul.unranked- list
and a div
descended from that li
."
Now is probably a good time to brush up on selectors. Play around on the MDN page, then come back when you're ready.
querySelectorAll
works a lot like querySelector()
— it accepts a selector
as its argument, and it searches starting from the element that it's called on
(or from document
) — but instead of returning the first match, it returns a
NodeList (which, remember, is not an Array) of all matching elements.
Given a document like
<main id="app">
<ul class="ranked-list">
<li>1</li>
<li>2</li>
</ul>
<ul class="ranked-list">
<li>10</li>
<li>11</li>
</ul>
</main>
If we called document.getElementById('app').querySelectorAll('ul.ranked-list li')
, we'd get back a list of Nodes corresponding to <li>1</li>
,
<li>2</li>
, <li>10</li>
, <li>11</li>
, we could change the content of these
li
s like so:
const lis = document
.getElementById('app')
.querySelectorAll('ul.ranked-list li');
for (let i = 0; i < lis.length; i++) {
lis[i].innerHTML = (i + 1).toString();
}
Now our li
s, even though they're children of two separate ul
s, will count up
from 1 to 4.
Using this loop construct, we could even, say, call querySelector()
or
querySelectorAll()
on these children to look deeper and deeper into a nested
structure... (hint!).
In index.html
, you'll see that we've set up a basic document for you. We'll be
testing against this document, but you should still write your code in
index.js
. We'll handle loading everything up for you.
-
Define a function
getFirstSelector(selector)
, which accepts a selector and returns the first element that matches. -
Define a function
nestedTarget()
that pulls a.target
out of#nested
(#
is used for IDs in selectors — but you knew that because you read the docs, right? :) ). (Note that inindex.html
#nested
and.target
just happen to bediv
s. This method should work with arbitrary elements.) -
Define a function
increaseRankBy(n)
that increases the ranks in all of the.ranked-list
s byn
. (You might need to make use ofparseInt()
-
Define a function
deepestChild()
that pulls out the most deeply nested child fromdiv#grand-node
. (Remember, you can iterate over elements and callquerySelector()
andquerySelectorAll()
on them. This is challenging to implement correctly, but not beyond your ability!)
HINT: Your solution for deepestChild()
does not need to be totally
generic; we don't expect it to work in every case. For example, we know that
div#grand-node
has only one node at each level — for this lab, you can solve
for that case, and not worry about a case where there are sibling nodes.
ADDITIONAL HINT: Remember learning about breadth-first search? A similar technique might come in handy here.