JavaScript (ES5) - Working With Selectors
Tags: javascript, beginners
Published: 2018-11-27 14:15:49

_This was originally posted on my site at https://martyhimmel.me on December 22, 2016. Like a number of others on dev.to, I've decided to move my technical blog posts to this site._

## DOM - Document Object Model

JavaScript works with HTML elements via the Document Object Model (DOM). You can think of the DOM as the hierarchical structure of HTML elements on a page. Here's an example of that structure:

```js
<html>
<head>
  <title>Page Title</title>
</head>
<body>
  <p id="foo">Some text in a paragraph</p>
  <ul class="my-list">
    <li>List Item 1</li>
    <li>List Item 2</li>
    <li>List Item 3</li>
  </ul>
</body>
</html>
```

JavaScript uses the DOM's structure to traverse, find, and manipulate elements. In the above example, the DOM structure states that the `head` and `body` elements are children of the `html` element, and the inverse - the `html` element is the parent of the `head` and `body` elements. This relationship is true for every element on the page (e.g. `ul` is the parent to the `li` elements, `p` is a child of the `body` element, etc.) and is important to know when using selectors.

The first step is usually done through the `document` selector methods. The `document` selectors allow you to get elements on a page and start working with them. For example:

```js
var paragraphFoo = document.getElementById('foo');
```

Would set `paragraphFoo` to this:

```html
<p id="foo">Some text in a paragraph</p>
```

Now, you have access to all the properties on that paragraph element. Here are a couple examples.

_Note: Anywhere `paragraphFoo` is used, `document.getElementById('foo')` could be used in its place. Setting the `paragraphFoo` var and using that is a slight performance boost - the DOM doesn't have to be queried/traversed every time we want to target that paragraph element._

```js
// element.innerHTML
// As a getter, it returns the current HTML inside of the opening and closing tags
paragraphFoo.innerHTML; // Some text in a paragraph

// As a setter, it changes the HTML inside the opening and closing tags
paragraphFoo.innerHTML = 'Change the paragraph text';
console.log(paragraphFoo); // <p id="foo">Change the paragraph text</p>
```

```js
// element.classList
// By itself, it returns an array of classes. You can also use element.classList.add() and
// element.classList.remove() to add and remove classes on the element.
paragraphFoo.classList; // []

paragraphFoo.classList.add('foo');
paragraphFoo.classList.add('bar');
paragraphFoo.classList; // ['foo', 'bar']

paragraphFoo.classList.remove('foo');
paragraphFoo.classList; // ['bar']
```

There are several more methods that can be used on an element. You can check the [Mozilla developer docs](https://developer.mozilla.org/en-US/docs/Web/API/Element) for a list of the available methods.

## Selectors

**Disclaimer**

_In this section, when I describe a selector as returning an array, that's technically not true. They're either an `HTMLCollection` or a `NodeList` of elements. They're not technically arrays, in that you can't use the array methods (`map`, `reduce`, etc.) on them, but you can loop through and access the individual elements the same way you would an array (`for` loop, bracket notation, etc). That also means when describing the `console.log()` result of one of these, it's not entirely accurate either. Instead of the full element (e.g. `[<li class="foo">]Some item</li>]`), it returns a dot notation version of the elements returned (e.g. `[li.foo]`). For simplicity's sake, I'm calling them arrays and using the full element. Just keep in mind that's not right from a technical standpoint, but is usable from a practical standpoint._

### getElementById

Takes an HTML id as an argument. Returns a single element.

```html
<p id="foo">Some text in a paragraph</p>
```

```js
var paragraphFoo = document.getElementById('foo');
console.log(paragraphFoo); // <p id="foo">Some text in a paragraph</p>
```

### getElementsByClassName

Takes an HTML/CSS class name as an argument. Returns an array of elements.

```html
<p class="bar">paragraph 1</p>
<p>paragraph 2</p>
<p class="bar">paragraph 3</p>
```

```js
var paragraphArray = document.getElementsByClassName('bar');
console.log(paragraphArray);
// [<p class="bar">paragraph 1</p>, <p class="bar">paragraph 3</p>]
```

### getElementsByTagName

Takes an HTML tag ('p', 'div', etc.) as an argument. Returns an array of elements.

```js
// Using the structure example near the top
var listItems = document.getElementsByTagName('li');
console.log(listItems);
// [<li>List Item 1</li>, <li>List Item 2</li>, <li>List Item 3</li>]
```

### getElementsByName

Takes a "name" attribute value as an argument. Returns an array of elements.

```html
<input name="first_name" type="text">
<input name="last_name" type="text">
```

```js
var firstName = document.getElementsByName('first_name');
console.log(firstName);
// [<input name="first_name" type="text>]
```

### querySelector

Takes a CSS style selector as an argument. Returns the first matching element.

```html
<p>I have <span class="num">2</span> cats.</p>
<div>I have <span class="num">3</span> dogs.</div>
```

```js
var spanNumOfCats = document.querySelector('p .num');
console.log(spanNumOfCats);
// <span class="num">2</span>
```

### querySelectorAll

Same as querySelector except that it returns an array containing all matched values.

```html
<p>I have <span class="num cats">2</span> cats.</p>
<p>I have <span class="num dogs">3</span> dogs.</p>
<p>I have <span class="num rabbits">4</span> rabbits.</p>
```

```js
var spanNonRabbitAnimals = document.querySelector('p .num:not(.rabbits)');
console.log(spanNonRabbitAnimals);
// [<span class="num cats">2</span>, <span class="num rabbits">4</span>]
```

In modern browsers and code, you'll generally only see/use `querySelector` and `querySelectorAll` as they greatly simplified the process and have made code a bit easier to read and understand. For example, if you need a single element with a class of `foo`, `document.querySelector('.foo');` is simpler than `document.getElementsByClassName('foo')[0];`.