JavaScript Searching:getElement*, querySelector*

As you already know, JavaScript DOM is a tree-like structure, made of all the elements existing in your HTML document.

What is essential is that the HTML elements are floating around in a way that you want to access and read data from or change it. There exist many ways of finding those elements.

In this chapter, you will find out what getElement* is used for, as well as the following two essential methods: querySelector and querySelectorAll.

Document.getElementById or Just ID

The navigation properties of DOM are excellent when they are close to each other. Otherwise, additional searching methods are used.

One of them is document.getElementById(id). You can use it when an element has the id attribute, no matter where it is.

The example of using document.getElementById(id) is as follows:

let div = document.createElement('div');
div.id = 'content';
div.innerHTML = '<p>Create Element example</p>';

document.body.appendChild(div);

document.getElementById('content').style.padding = '10px';

document.getElementById('content').style.background = 'yellow';

document.getElementById('content').style.color = 'red';

You can also use a global variable, named by id, which references the element. The example will look like this:

let div = document.createElement('div');
div.id = 'content';
div.innerHTML = '<p>Create Element example</p>';
document.body.appendChild(div);	
// content is a reference to DOM-element with id="content"
content.style.padding = '10px';
content.style.background = 'yellow';
content.style.color = 'red';

That works unless a JavaScript variable with the same name is declared. Then it takes precedence, like here:

let div = document.createElement('div');
div.id = 'elem';

document.body.appendChild(div);
let elem = 10; // now elem is 10, not a reference to <div id="elem">
console.log(elem); // 10

Please, note that id should be unique. There can be only a single element in the document with the given id. In case, different elements have the same id, the behavior of the methods that use it is unpredictable. It means that document.getElementById can return any of those elements at random.

querySelectorAll

The most flexible method elem.querySelectorAll(css) returns all the elements inside elem matching the particular CSS selector.

In the example below, the last children elements, are looked for:

let div = document.createElement('div');
div.id = 'elem';
document.body.appendChild(div);
let names = ['javascript', 'html', 'css', 'git'];
let ul = document.createElement('ul');
document.getElementById('elem').appendChild(ul);
names.forEach(function (name) {
  let li = document.createElement('li');
  ul.appendChild(li);
  li.innerHTML += name;
});
let elements = document.querySelectorAll('ul > li:last-child');
for (let elem of elements) {
  console.log(elem.innerHTML); // "git"
}

Definitely, it’s a powerful method, as you can use any CSS selector. Pseudo-classes in the CSS selector, such as :hover and :active are supported, as well. For example, document.querySelectorAll(':hover') can return the collection with elements that the pointer is over.

querySelector

The call to elem.querySelector(css) may return the initial element for the particular CSS selector. So, the result is equivalent to elem.querySelectorAll(css)[0], but the latter is searching for all the elements and picking one, while elem.querySelector, as a rule, looks for one. So, it’s much faster to write.

Matches

The methods above are used for searching the DOM. The elem.matches(css), doesn’t look for anything but checks whether el matches the particular CSS selector. It returns either true or false.

It comes handy when you iterate over elements trying to filter out the ones that interest you.

Let’s have a look at the example below:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
  </head>
  <body>
    <a href="http://example.com/example.zip">Example</a>
    <a href="http://w3docs.com">W3Docs</a>
    <script>
      // can be any collection instead of document.body.children
       for (let elem of document.body.children) {
        if (elem.matches('a[href$="zip"]')) {
          alert("The archive reference: " + elem.href );
        }
      }
    </script>
  </body>
</html>

Closest

An element’s ancestors are parent, the parent of the parent, its parent, and so on. Together the ancestors build the chain of parents from the element to top. The elem.closest(css) watches the closest ancestor that matches the CSS-selector. The elem is involved in the search, as well. That is to say, the method closest goes up from the element, checking each of the parents. When it matches the selector, the search finishes, and the ancestor is returned.

The example of using the closest is the following:

let h1 = document.createElement('h1');
h1.innerHTML = 'Books';
document.body.appendChild(h1);
let div = document.createElement('div');
div.class = 'content';
div.id = 'elem'
document.body.appendChild(div);
let bookNames = ['javascript', 'html', 'css', 'git'];
let ul = document.createElement('ul');
ul.id = 'book'
document.getElementById('elem').appendChild(ul);
bookNames.forEach(function (name) {
  let li = document.createElement('li');
  ul.appendChild(li);
  li.innerHTML += name;
  li.id = 'chapter'
});
let chapter = document.querySelector('#chapter');
alert(chapter.closest('#book'));
alert(chapter.closest('#elem'));
alert(chapter.closest('h1')); // null, because h1 isn't an ancestor

getElementsBy*

Let’s explore other methods, as well, that are mostly history, but can be found in old scripts.

Among them are:

  1. elem.getElementsByTagName(tag): it looks for element with a particular tag returning the collection of them. The tag parameters may also be "*".
  2. elem.getElementsByClassName(className): it returns the elements with the given CSS class.
  3. document.getElementsByName(name): this one returns elements with particular name attribute, document-wide.

Live Collections

Any "getElementsBy*" method returns a live collection. These collections reflect the current state of the document “auto-updating” it when it changes.

Below you can find to scripts:

let div1 = document.createElement('div');
document.body.appendChild(div1);
let divs = document.getElementsByTagName('div');
alert(divs.length); // 1
let div2 = document.createElement('div');
document.body.appendChild(div2);
alert(divs.length); // 2

The first script creates a reference to the <div> collection ( the length is 1). The second one runs after the browser sees one more <div> ( the length is 2).

On the contrary, querySelectorAll returns a static collection: like a fixed array of elements.

Using it instead will make the output of both scripts 1, like here:

let div1 = document.createElement('div');
document.body.appendChild(div1);
let divs = document.querySelectorAll('div');
alert(divs.length); // 1
let div2 = document.createElement('div');
document.body.appendChild(div2);
alert(divs.length); // 1

Now, the difference is noticeable.

Summary

Totally, there are six methods of searching for nodes in DOM. They are the following:

  1. querySelector
  2. querySelectorAll
  3. getElementById
  4. getElementsByName
  5. getElementsByTagName
  6. getElementsByClassName

The most used ones are the querySelector and querySelectorAll. However, getElementBy* comes in handy in the old scripts.

The first two methods are extremely useful in complex documents. In this kind of documents, it is not so easy to target a specific element.




Do you find this helpful?

Related articles