Skip to content

Commit 092f739

Browse files
committed
searching elements: make more modern
1 parent b8eb04d commit 092f739

File tree

1 file changed

+113
-120
lines changed
  • 2-ui/1-document/04-searching-elements-dom

1 file changed

+113
-120
lines changed

2-ui/1-document/04-searching-elements-dom/article.md

Lines changed: 113 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
# Searching: getElement* and querySelector*
1+
# Searching: getElement*, querySelector*
22

33
DOM navigation properties are great when elements are close to each other. What if they are not? How to get an arbitrary element of the page?
44

55
There are additional searching methods for that.
6+
67
## document.getElementById or just id
78

89
If an element has the `id` attribute, then there's a global variable by the name from that `id`.
910

10-
We can use it to access the element, like this:
11+
We can use it to immediately access the element no matter where it is:
1112

1213
```html run
1314
<div id="*!*elem*/!*">
@@ -24,7 +25,9 @@ We can use it to access the element, like this:
2425
</script>
2526
```
2627

27-
That's unless we declare the same-named variable by our own:
28+
The behavior is described [in the specification](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem), but it is supported mainly for compatibility. The browser tries to help us by mixing namespaces of JS and DOM. Good for very simple scripts, but there may be name conflicts. Also, when we look in JS and don't have HTML in view, it's not obvious where the variable comes from.
29+
30+
If we declare a variable with the same name, it takes precedence:
2831

2932
```html run untrusted height=0
3033
<div id="elem"></div>
@@ -36,8 +39,6 @@ That's unless we declare the same-named variable by our own:
3639
</script>
3740
```
3841

39-
The behavior is described [in the specification](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem), but it is supported mainly for compatibility. The browser tries to help us by mixing namespaces of JS and DOM. Good for very simple scripts, but there may be name conflicts. Also, when we look in JS and don't have HTML in view, it's not obvious where the variable comes from.
40-
4142
The better alternative is to use a special method `document.getElementById(id)`.
4243

4344
For instance:
@@ -68,104 +69,9 @@ If there are multiple elements with the same `id`, then the behavior of correspo
6869
The method `getElementById` that can be called only on `document` object. It looks for the given `id` in the whole document.
6970
```
7071
71-
## getElementsBy*
72-
73-
There are also other methods to look for nodes:
74-
75-
- `elem.getElementsByTagName(tag)` looks for elements with the given tag and returns the collection of them. The `tag` parameter can also be a star `"*"` for "any tags".
76-
77-
For instance:
78-
```js
79-
// get all divs in the document
80-
let divs = document.getElementsByTagName('div');
81-
```
82-
83-
This method is callable in the context of any DOM element.
84-
85-
Let's find all `input` tags inside the table:
86-
87-
```html run height=50
88-
<table id="table">
89-
<tr>
90-
<td>Your age:</td>
91-
92-
<td>
93-
<label>
94-
<input type="radio" name="age" value="young" checked> less than 18
95-
</label>
96-
<label>
97-
<input type="radio" name="age" value="mature"> from 18 to 50
98-
</label>
99-
<label>
100-
<input type="radio" name="age" value="senior"> more than 60
101-
</label>
102-
</td>
103-
</tr>
104-
</table>
105-
106-
<script>
107-
*!*
108-
let inputs = table.getElementsByTagName('input');
109-
*/!*
110-
111-
for (let input of inputs) {
112-
alert( input.value + ': ' + input.checked );
113-
}
114-
</script>
115-
```
116-
117-
```warn header="Don't forget the `\"s\"` letter!"
118-
Novice developers sometimes forget the letter `"s"`. That is, they try to call `getElementByTagName` instead of <code>getElement<b>s</b>ByTagName</code>.
119-
120-
The `"s"` letter is absent in `getElementById`, because it returns a single element. But `getElementsByTagName` returns a collection of elements, so there's `"s"` inside.
121-
```
122-
123-
````warn header="It returns a collection, not an element!"
124-
Another widespread novice mistake is to write:
125-
126-
```js
127-
// doesn't work
128-
document.getElementsByTagName('input').value = 5;
129-
```
130-
131-
That won't work, because it takes a *collection* of inputs and assigns the value to it rather than to elements inside it.
132-
133-
We should either iterate over the collection or get an element by its index, and then assign, like this:
134-
135-
```js
136-
// should work (if there's an input)
137-
document.getElementsByTagName('input')[0].value = 5;
138-
```
139-
````
140-
141-
There are also other rarely used methods of this kind:
142-
143-
- `elem.getElementsByClassName(className)` returns elements that have the given CSS class. Elements may have other classes too.
144-
- `document.getElementsByName(name)` returns elements with the given `name` attribute, document-wide. Exists for historical reasons, very rarely used, we mention it here only for completeness.
145-
146-
For instance:
147-
148-
```html run height=50
149-
<form name="my-form">
150-
<div class="article">Article</div>
151-
<div class="long article">Long article</div>
152-
</form>
153-
154-
<script>
155-
// find by name attribute
156-
let form = document.getElementsByName('my-form')[0];
157-
158-
// find by class inside the form
159-
let articles = form.getElementsByClassName('article');
160-
alert(articles.length); // 2, found two elements with class "article"
161-
</script>
162-
```
163-
16472
## querySelectorAll [#querySelectorAll]
16573
166-
Now goes the heavy artillery.
167-
168-
The call to `elem.querySelectorAll(css)` returns all elements inside `elem` matching the given CSS selector. That's the most often used and powerful method.
74+
By far, the most versatile method, `elem.querySelectorAll(css)` returns all elements inside `elem` matching the given CSS selector.
16975
17076
Here we look for all `<li>` elements that are last children:
17177
@@ -195,7 +101,6 @@ This method is indeed powerful, because any CSS selector can be used.
195101
Pseudo-classes in the CSS selector like `:hover` and `:active` are also supported. For instance, `document.querySelectorAll(':hover')` will return the collection with elements that the pointer is over now (in nesting order: from the outermost `<html>` to the most nested one).
196102
```
197103

198-
199104
## querySelector [#querySelector]
200105

201106
The call to `elem.querySelector(css)` returns the first element for the given CSS selector.
@@ -230,9 +135,7 @@ For instance:
230135

231136
## closest
232137

233-
All elements that are directly above the given one are called its *ancestors*.
234-
235-
In other words, ancestors are: parent, the parent of parent, its parent and so on. The ancestors together form the chain of parents from the element to the top.
138+
*Ancestors* of an element are: parent, the parent of parent, its parent and so on. The ancestors together form the chain of parents from the element to the top.
236139

237140
The method `elem.closest(css)` looks the nearest ancestor that matches the CSS-selector. The `elem` itself is also included in the search.
238141

@@ -260,6 +163,98 @@ For instance:
260163
</script>
261164
```
262165

166+
## getElementsBy*
167+
168+
There are also other methods to look for nodes by a tag, class, etc.
169+
170+
Today, they are mostly history, as `querySelector` is more powerful and shorter to write.
171+
172+
So here we cover them mainly for completeness, while you can still find them in the old scripts.
173+
174+
- `elem.getElementsByTagName(tag)` looks for elements with the given tag and returns the collection of them. The `tag` parameter can also be a star `"*"` for "any tags".
175+
- `elem.getElementsByClassName(className)` returns elements that have the given CSS class. Elements may have other classes too.
176+
- `document.getElementsByName(name)` returns elements with the given `name` attribute, document-wide. very rarely used.
177+
178+
For instance:
179+
```js
180+
// get all divs in the document
181+
let divs = document.getElementsByTagName('div');
182+
```
183+
184+
Let's find all `input` tags inside the table:
185+
186+
```html run height=50
187+
<table id="table">
188+
<tr>
189+
<td>Your age:</td>
190+
191+
<td>
192+
<label>
193+
<input type="radio" name="age" value="young" checked> less than 18
194+
</label>
195+
<label>
196+
<input type="radio" name="age" value="mature"> from 18 to 50
197+
</label>
198+
<label>
199+
<input type="radio" name="age" value="senior"> more than 60
200+
</label>
201+
</td>
202+
</tr>
203+
</table>
204+
205+
<script>
206+
*!*
207+
let inputs = table.getElementsByTagName('input');
208+
*/!*
209+
210+
for (let input of inputs) {
211+
alert( input.value + ': ' + input.checked );
212+
}
213+
</script>
214+
```
215+
216+
```warn header="Don't forget the `\"s\"` letter!"
217+
Novice developers sometimes forget the letter `"s"`. That is, they try to call `getElementByTagName` instead of <code>getElement<b>s</b>ByTagName</code>.
218+
219+
The `"s"` letter is absent in `getElementById`, because it returns a single element. But `getElementsByTagName` returns a collection of elements, so there's `"s"` inside.
220+
```
221+
222+
````warn header="It returns a collection, not an element!"
223+
Another widespread novice mistake is to write:
224+
225+
```js
226+
// doesn't work
227+
document.getElementsByTagName('input').value = 5;
228+
```
229+
230+
That won't work, because it takes a *collection* of inputs and assigns the value to it rather than to elements inside it.
231+
232+
We should either iterate over the collection or get an element by its index, and then assign, like this:
233+
234+
```js
235+
// should work (if there's an input)
236+
document.getElementsByTagName('input')[0].value = 5;
237+
```
238+
````
239+
240+
Looking for `.article` elements:
241+
242+
```html run height=50
243+
<form name="my-form">
244+
<div class="article">Article</div>
245+
<div class="long article">Long article</div>
246+
</form>
247+
248+
<script>
249+
// find by name attribute
250+
let form = document.getElementsByName('my-form')[0];
251+
252+
// find by class inside the form
253+
let articles = form.getElementsByClassName('article');
254+
alert(articles.length); // 2, found two elements with class "article"
255+
</script>
256+
```
257+
263258
## Live collections
264259
265260
All methods `"getElementsBy*"` return a *live* collection. Such collections always reflect the current state of the document and "auto-update" when it changes.
@@ -327,6 +322,18 @@ There are 6 main methods to search for nodes in DOM:
327322
</thead>
328323
<tbody>
329324
<tr>
325+
<td><code>querySelector</code></td>
326+
<td>CSS-selector</td>
327+
<td>✔</td>
328+
<td>-</td>
329+
</tr>
330+
<tr>
331+
<td><code>querySelectorAll</code></td>
332+
<td>CSS-selector</td>
333+
<td>✔</td>
334+
<td>-</td>
335+
</tr>
336+
<tr>
330337
<td><code>getElementById</code></td>
331338
<td><code>id</code></td>
332339
<td>-</td>
@@ -350,24 +357,10 @@ There are 6 main methods to search for nodes in DOM:
350357
<td>✔</td>
351358
<td>✔</td>
352359
</tr>
353-
<tr>
354-
<td><code>querySelector</code></td>
355-
<td>CSS-selector</td>
356-
<td>✔</td>
357-
<td>-</td>
358-
</tr>
359-
<tr>
360-
<td><code>querySelectorAll</code></td>
361-
<td>CSS-selector</td>
362-
<td>✔</td>
363-
<td>-</td>
364-
</tr>
365360
</tbody>
366361
</table>
367362
368-
Please note that methods `getElementById` and `getElementsByName` can only be called in the context of the document: `document.getElementById(...)`. But not on an element: `elem.getElementById(...)` would cause an error.
369-
370-
Other methods can be called on elements too. For instance `elem.querySelectorAll(...)` will search inside `elem` (in the DOM subtree).
363+
By far the most used are `querySelector` and `querySelectorAll`, but `getElementBy*` can be sporadically helpful or found in the old scripts.
371364
372365
Besides that:
373366

0 commit comments

Comments
 (0)