The main use of client-side JavaScript is to manipulate web pages dynamically. We can do this with the DOM traversal methods and properties available to DOM Node objects.
Adding or changing child and sibling elements is easy for any given element since there are properties built into DOM node objects to do so. The following are methods of a DOM node object for getting parent, child and sibling nodes or elements.
Below are more useful DOM traversal methods.
hasChildNodes
The hasChildNodes
method returns a boolean that indicates whether the node it’s called on has any child nodes. Nodes include all kinds of nodes like element, text and comment nodes
For example, given the following HTML:
<div></div>
Then we can call hasChildNodes
on it as follows:
const div = document.querySelector('div');
console.log(div.hasChildNodes())
We should get false
since the div has no child nodes.
On the other hand, if we have:
<div>
foo
</div>
Then hasChildNodes
returns true
since there’s a text node inside the div.
insertBefore
The insertBefore
method lets us add a node before the node that this method called on. It takes 2 arguments. The first is the new node to be inserted. The second is the node before the new node that it’s inserted, which is called the reference node.
If the reference node is null
, then it’ll be inserted at the end of the list of child nodes.
It returns the add child except when the new node is a DocumentFragement
. In that case, only DocumentFragement
is returned.
For example, given the following HTML:
<div id='foo'>
foo
<div id='bar'>
bar
</div>
</div>
We can add a new div element after the div with ID bar inside the one with ID foo by writing:
const foo = document.querySelector('#foo');
const newDiv = document.createElement('div');
newDiv.textContent = 'new';
foo.insertBefore(newDiv, null);
The HTML structure looks like:
<div id="foo">
foo
<div id="bar">
bar
</div>
<div>new</div>
</div>
after insertBefore
is called.
If we pass in the second argument, then the element in the first argument will be inserted before the second one.
For example, given the following HTML:
<div id='foo'>
foo
<div id='bar'>
bar
</div>
</div>
Then we can insert an element before the one with ID bar at the same level by writing:
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');
const newDiv = document.createElement('div');
newDiv.textContent = 'new';
foo.insertBefore(newDiv, bar);
Then we get the following HTML after insertBefore
is called:
<div id="foo">
foo
<div>new</div>
<div id="bar">
bar
</div>
</div>
isEqualNode
The isEqualNode
method checks whether 2 nodes are equal. They’re equal when they have the same type, defining characteristics like ID, the number of children, the same attributes, etc. The data points for comparison vary depending on the types of nodes.
It takes one argument, which is the node that we want to compare with.
For example, given the following HTML:
<div id='foo'>
foo
</div>
<div id='bar'>
bar
</div>
Then we can write the following JavaScript to check if the div with ID foo and the div with ID bar are the same:
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');
console.log(foo.isEqualNode(bar));
The console.log
should log false
since they don’t have the same ID or content.
On the other hand, if we have the following HTML:
<div class='foo'>
foo
</div>
<div class='foo'>
foo
</div>
Then we can compare them by writing:
const foo1 = document.querySelector('.foo:nth-child(1)');
const foo2 = document.querySelector('.foo:nth-child(2)');
console.log(foo1.isEqualNode(foo2));
and the console.log
should log true
since they have identical class value and content.
isSameNode
The isSameNode
method checks whether 2 Node objects reference the same node.
It takes one argument, which is the other node to test and returns a boolean indicating whether they’re the same.
For example, given the following HTML:
<div>
foo
</div>
We can call isSameNode
by writing:
const div = document.querySelector('div');console.log(div.isSameNode(div));
On the other hand, if we have:
<div>
foo
</div>
<div>
foo
</div>
Then the following call to isSameNode
will return false
:
const div1 = document.querySelector('div:nth-child(1)');
const div2 = document.querySelector('div:nth-child(2)');console.log(div1.isSameNode(div2));
This is because even though they look the same, they don’t reference the same node.
normalize
The normalize
method cleans up the sub-tree of a Node by removing adjacent text nodes.
For example, if we have the following HTML:
<div>
foo
</div>
Then before call normalize
, we get that there’re 3 child nodes inside the div element after add 2 more text nodes to it as child nodes of the div. After we called it, it’s reducing the number of child nodes to 1.
We call as in the following code:
const div = document.querySelector('div');
div.appendChild(document.createTextNode("foo "));
div.appendChild(document.createTextNode("bar"));console.log(div.childNodes.length);
div.normalize();
console.log(div.childNodes.length);
The first console.log
should log 3 and the second one should log 1.
removeChild
To remove the child node from a given node, we can use the removeChild
method to remove the child from the DOM tree.
It takes a child element of the given node as an argument and then returns the node that was removed from the DOM tree.
For example, given that we have the following HTML:
<div id='foo'>
foo
<div id='bar'>
bar
</div>
</div>
We can remove the div with ID bar by writing:
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');foo.removeChild(bar);
Then we should no longer see ‘bar’ in the browser window.
It only works with child nodes. For example, if we have:
<div id='foo'>
foo
</div>
<div id='bar'>
bar
</div>
and run the same code, then we’ll get the error ‘Uncaught DOMException: Failed to execute ‘removeChild’ on ‘Node’: The node to be removed is not a child of this node.’
It’ll also throw an error if the node doesn’t exist.
replaceChild
The replaceChild
method replaces the current one with the second one given in the parameter.
For example, if we have the following HTML:
<div id='foo'>
foo
<div id='bar'>
bar
</div>
</div>
Then we can create a new element to replace the div with ID bar:
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');const baz = document.createElement('div');
baz.textContent = 'baz';
foo.appendChild(baz);foo.replaceChild(baz, bar);
The first argument has the new element and the second argument has the original one.
It also works for using elements that already exist to replace another one that exists.
For instance, if we have the following HTML:
<div id='foo'>
foo
<div id='bar'>
bar
</div>
<div id='baz'>
baz
</div>
</div>
Then we can write:
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');
const baz = document.querySelector('#baz');
foo.replaceChild(baz, bar);
to replace the div with ID bar with the one with ID baz.
The DOM traversal and manipulation methods are very useful. We can use them to check if they have the same content or referencing the same element. Also, there’re methods to replace nodes and clean up extraneous text nodes. There are also handy methods for inserting nodes and removing nodes.