Manipulating the DOM using Javascript - traversing the DOM(part 2)✂️🕹
Tags: javascript, html, webdev, beginners
Published: 2022-08-19 05:56:54


In the last article we learned what the DOM is and that it can be manipulated (change the nodes inside it). We also learned about one way we can target DOM nodes using different selectors (if you didn't read the first article of the series, I recommend doing so  before going any further). We basically learned how to make use of the built-in methods of the document object to access HTML elements by `class, id, tage name or query selectors.` 

Another way of targeting nodes is by traversing the DOM. Traversing simply means to `move throught` the DOM using the relation between nodes (when having access to a certain DOM node, we can reach its related nodes). This means we can stay on the same DOM level (branch) while moving up, down or even sideways. 

But why would we need to do that? We would think that using `document.querySelector()` would be enough for every situation we encounter when trying to manipulate the DOM. Well, yes and no. 

#### Let's think of an analogy

Imagine you are inside of your favorite book store, where the books in a series are sorted in ascending order, from left to right. You are looking at the first Harry Potter volume that's sitting on a shelf. You're missing the first two volumes and you would like to buy them, so after you found the first one, you know the second should be next to it. Now you have two possibilities to get the second volume:

- You get it directly from the shelf, since you can move a bit to the right and find it right away.
- You go to the cash register and ask for the person working there to look for the book in their system, tell you where in the store it's located and then go get it.

Which approach would be faster? The first one, of course. We found the second volume based on the position (relation) to the first one, instead of interogating the system (do a search by name). Based on this analogy, it will always be easier to move from one node to the other than doing a full search.

### TRAVERSING THE DOM
Before moving forward, let's write some simple HTML code so we can visualize our examples better:

```HTML
<!DOCTYPE html>
<html>
 <head>
   <title>Traversing the DOM is fun!</title>
 </head>
 <body>
  <h2>How to</h2>
  <p>If you want to learn how to traverse the DOM, you should continue reading this 
   tutorial.</p>
  <h2>We can traverse the DOM based on the relation between:</h2>
  <ul id="nodesList">
    <li>Parent nodes</li>
    <li>Children nodes</li>
    <li>Siblings nodes</li>
  </ul>
 </body>
</html>
```
A real representation of the DOM based on the above HTML looks like bellow (if you want to generate real DOM trees, you can use [this tool](https://software.hixie.ch/utilities/js/live-dom-viewer/))

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4oukuvxy7cmoc6f4ndi6.JPG)

We can traverse the DOM based on the relation between `parent, children and sibling nodes`. We have the first node in the tree which is called the `root node`. This is the only node that doesn't have a parent since it's positioned on the highest level. Every other node has exactly one parent and can have any number of children. We call nodes with the same parent sibling nodes. 

In our example above, the simplest parent-child relationship between nodes is:
- the `document` is the `root node` and it has two children: the `DOCTYPE declaration` and the `html`
- the `html` is the parent of `head` and `body`
- the `body` is the parent of `h2`, `p`, `h2` and `ul`
- the `ul` is parent to the `li`s

Also, let's remember that everything in an HTML document is considered a node and we have:
- the Document, which in itself is `a node`
- HTML elements, which are `Element Nodes`
- the text inside the HTML elements, which are `Text Nodes`
- comments, which are `Comment Nodes`

### TRAVERSING BASED ON THE PARENT NODE RELATION
A `parent node` is any node that is one level above another node, or closer to the document node in the DOM hierarchy. There are two ways to get the parent of a node: `parentNode` and `parentElement`. So, in our example, if we would want to get the parent node of the first `h2`, we would say:

```Javascript
// first we target the h2 tag
const headerTwo = document.getElementsByTagName("h2")[0];
const parent = headerTwo.parentNode;
console.log(parent);
► (1) [body]
```
What we are going to get is the `<body></body>` tag, since it's  one level above the `<h2></h2>` tag. If we want to go even one more level up, we can chain multiple `parentNode` properties, like so:

```Javascript
const headerTwo = document.getElementsByTagName("h2")[0];
const parent = headerTwo.parentNode.parentNode;
console.log(parent);
► (1) [html]
```
Now we 'll be targeting the `<html></html>` tag since it's one level above the `<body></body>`.

### TRAVERSING BASED ON THE CHILDREN NODES RELATION
The children of a node are considered to be all nodes that are positioned one level bellow that node (that is one level of nesting).

The properties that help us target children nodes are: `childNodes`, `firstChild`, `lastChild`, `children`, `firstElementChild` and `lastElementChild`. 

#### An interesting situation
If we would want to target the children of the `<body></body>` element in our example, we would probably say:

```javascript
const bodyChildren = document.body.childNodes;
console.log(bodyChildren);
```
I assume you would expect to see a list of four items printed to the console.

```javascript
► (4) [h2, p, h2, ul]
```

Instead you will see this:

```javascript
► (9) [text, h2, text, p, text, h2, tex, ul, text]
```

This is happening because the `childNodes` property is targeting all nodes, including text nodes. In our example, the indentation between the HTML lines of code are interpreted as text.

I think now is the perfect time to clarify what `nodes` (which were targeted by the childNodes property) and `elements` (h2, p, h2, ul, which we were expecting to see in the console) are. 

>A node is any object represented in the DOM. Nodes can be of multiple types but the ones we are going to encounter most often are `document`, `element` and `text`. So, elements are just nodes of the type `element`. A complete list of all node types can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType). 

Coming back to out example, where instead of four nodes we got back nine, this is because `childNodes` selects all node types (including text), not only the `element` ones, which we were interested in. 

If we want to select only the children of the type `node element`, we can use the `children`, `firstElementChild` and `lastElementChild` properties. So, to rewrite our example:

```javascript
const bodyChildren = document.body.children;
console.log(bodyChildren);
► (4) [h2, p, h2, ul]
```

### TRAVERSING BASED ON THE SIBLING NODES RELATION

A `sibling node` is any node that is on the same DOM level with any other node. In our example, `h2, p, h2 and ul` are all siblings since they are on the same DOM level. The property we can use to select sibling nodes are: `previousSibling`, `nextSibling`, `previousElementSibling` and `nextElementSibling`. Keep in mind that, just like in the case of child nodes, `previousSibling` and `nextSibling` select siblings of any type, whether `previousElementSibling` and `nextElementSibling` will only select nodes of type element.

So, if we want to select the second `<li>` element in the `<ul>`, we need to write:

```javascript
// we target the list based on its id
const list = document.getElementById("nodesList");
// we target the first node of element type
const firstElement = list.firstElementChild;
// we use nextElementSibling to get to the second list item
const thirdElement = firstElement.nextElementSibling;
console.log(thirdElement )
► (1) [li]
```

If instead we would have used the `nextSibling` property, the return value would have been a `text node` since the indentation in the HTML is considered text, so we would have targeted white space (a node of type text) instead of the next list item element.

```javascript
const thirdElement = firstElement.nextSibling;
console.log(thirdElement )
► (1) [text]
```

Now that we know how to traverse the DOM, in the next article we will focus on how we can actually change things in the DOM, with examples. See you next time!

*Header source image: [Paul Esch-Laurent](https://unsplash.com/photos/oZMUrWFHOB4) on [Unsplash](https://unsplash.com/@pinjasaur)*

Refrence articles:
- [Node.nodeType](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType)
- [Traversing the DOM](https://www.w3.org/wiki/Traversing_the_DOM)
- [Traversing the Document Object Model with JavaScript](https://www.linode.com/docs/guides/traversing-the-dom/)