Making websites dynamic is important for a lot of websites. Many of them have animations and dynamically display data. To change data without refreshing the page, we have to manipulate the document being displayed. Web pages are displayed in the browser by parsing them in the tree model called the Document Object Model (DOM).
The DOM tree is made up of individual components, called nodes. All web pages’ DOMs start with the root node, which is the document node. The node under the document node is the root element node.
For web pages, the root element node is the HTML node. Below that, every other node is under the HTML node, and there lie nodes below some of the nodes which are linked to the parent node. Together, the nodes form something that’s like an inverted tree.
There are several types of nodes in the DOM:
- Document node — the root of the DOM in all HTML documents
- Element node — the HTML elements
- Attribute nodes — attributes of the element nodes
- Text nodes — text content of HTML elements
- Comment nodes — HTML comments in a document
Relationship of Nodes
The DOM is a tree with a root node and elements linked to the root node.
Every node has one parent node — except the root node. Each node can have one or more children. Nodes can also have siblings that reside at the same level of the given node.
If there are multiple elements of the same type, then you can get the node by getting the same type of node as a node list and then get the one you want by its index. A node list looks like an array, but it’s not one. You can loop through the elements of a node list, but array methods aren’t available in node lists.
For example, if we have the following HTML document …
<html>
<head>
<title>HTML Document</title>
</head>
<body>
<section>
<p>First</p>
<p>Second</p>
<p>Third</p>
</section>
</body>
</html>
… then we can get the document p
tags, by adding the following:
const list = document.body.childNodes\[1\].childNodes;
for (let i = 0; i < list.length; i++) {
console.log(list)
}
In the script of the document to get the nodes, the script gets the body and then gets the second child node (which is the section
tag). Then it gets the child node by accessing the childNodes
property again, which will get the p
tags.
Together, we have:
<html>
<head>
<title>HTML Document</title>
</head>
<body>
<section>
<p>First</p>
<p>Second</p>
<p>Third</p>
</section>
<script>
const list = document.body.childNodes[1].childNodes;
for (let i = 0; i < list.length; i++) {
console.log(list)
}
</script>
</body>
</html>
There are also convenience properties for accessing the first and last child and siblings of elements of a given node.
In a node element, we have the firstChild
property to get the first child of a node. In the lastChild
property, we can get the last child of a given node. nextSibling
gets the next child node in the same parent node, and previousSibling
gets the previous child node of the same parent node.
Each node has some properties and methods that allow us to get and set properties of a node. They are the following:
anchors
gets a list of all anchors, elements with name attributes, in the documentapplets
gets an ordered list of all the applets in the documentbaseURI
gets the base URI of the documentbody
gets the<body>
or the<frameset>
node of the document bodycookie
gets/sets a key value pair in the browser cookiedoctype
gets the document type declaration of a documentdocumentElement
gets the root document elementdocumentMode
gets the mode used by the browser to render the documentdocumentURI
gets/sets the location of the documentdomain
gets the domain name of the server that loaded the documentembeds
gets all theembed
elements in the documentforms
gets all theform
elements in the documenthead
gets thehead
element of the documentimages
gets all theimg
elements in the documentimplementation
gets theDOMImplementation
object that handles the documentlastModified
gets the latest date and time the document was modifiedlinks
gets allarea
anda
tags that contain thehref
attributereadyState
gets the loading status of the document.readyState
isloading
when the document is loading,interactive
when the document finishes parsing, andcomplete
when it completes loading.referrer
gets the URL the current document is loaded fromscripts
get thescript
elements in the documenttitle
get thetitle
element of the documentURL
get the URL of of the document
The DOM has methods to get and manipulate elements and handle events by attaching event handlers. The methods are below:
addEventListener()
attaches an event handler to the documentadoptNode()
adopts a node from another documentclose()
closes the output writing stream of the document that was previously opened withdocument.open()
createAttribute()
creates an attribute nodecreateComment()
creates a common nodecreateDocumentFragment()
creates an empty document fragmentcreateElement()
creates an element nodecreateTextNode()
creates a text nodegetElementById()
gets an element in the document with the given IDgetElementByClassName()
gets all elements with the given class namegetElementByName()
gets all elements with the given name attributegetElementsByTagName()
gets all elements with the given tag nameimportNode()
imports a node from another documentnormalize()
clears the text node and joins together adjacent nodesquerySelector()
gets one element with the given CSS selector(s)querySelectorAll()
gets all elements with the given CSS selector(s)removeEventListener()
removes an event handler that’s been added using theaddEventListener()
method from the documentrenameNode()
renames an existing nodewrite()
write JavaScript or HTML code to a documentwriteln()
write JavaScript or HTML code to a document and adds a new line after each statement
Element objects have special properties that can be get or set to modify the given element. The are:
accessKey
gets/sets theaccessKey
attribute of an elementattributes
gets all attributes of a nodechildElementCount
gets the number of child elements of a nodechildNodes
gets the child nodes of a nodechildren
gets the child elements of an elementclassList
gets all the class names of an elementclassName
gets or sets the class names of an elementclientHeight
gets the height of an element including paddingclientLeft
gets the left border width of an elementclientTop
gets the top border width of an elementclientWidth
gets the width of an element including paddingcontentEditable
gets or sets whether content is editabledir
gets or sets thedir
attribute of an elementfirstChild
gets the first child node of an elementfirstElementChild
gets the first child element of an elementid
gets or sets the ID of an elementinnerHTML
gets or sets the content of an elementisContentEditable
gets whether the content ID is editable as a Booleanlang
gets or sets the language of the element or attributelastChild
gets the last child node of an elementlastElementChild
gets the last child element of an elementnamespaceURI
gets the namespace URI of the first node of an elementnextSibling
gets the next node at the same node levelnextElementSibling
gets the next element at the same levelnodeName
gets the selected node’s namenodeType
gets the node typenodeValue
gets the value of the nodeoffsetHeight
gets the height of the node, which includes padding, borders, and the scrollbaroffsetWidth
gets the width of the node, which includes padding, borders, and the scrollbaroffsetLeft
gets the horizontal offset of an elementoffsetParent
gets the offset container of an elementoffsetTop
gets the vertical offset of an elementownerDocument
gets the root element of an elementparentNode
gets the parent node of an elementparentElement
gets the parent element of an elementpreviousSibling
gets the previous node of an elementpreviousElementSibling
gets the previous element of an element at the same levelscrollHeight
gets the height of an element, including paddingscrollLeft
gets the number of pixels of the element that has been scrolled horizontallyscrollTop
gets the number of pixels of the element that has been scrolled verticallyscrollWidth
gets the width of an element, including paddingstyle
gets the CSS styles of the elementtabIndex
gets thetabindex
attribute of an elementtagName
gets the tag name of an elementtextContent
gets or sets the text content of an elementtitle
gets or sets thetitle
attribute of an elementlength
gets the number of nodes in a NodeList
An element has the following methods for manipulating it:
addEventLIstener()
attaches an event handler to an elementappendChild()
adds a child node to an element at the endblur()
removes the focus from an elementclick()
clicks on an elementcloneNode()
clones the given nodecompareDocumentPosition()
compares the position of two elementscontains()
checks if an element has a given nodefocus()
focuses on an elementgetAttribute()
gets an attribute of an elementgetAttributeNode()
gets an attribute of an elementgetElementsByClassName()
gets an element with the given class namegetElementByTagName()
gets an element with the given tag namegetFeature()
gets an object that implements the API of a given featurehasAttribute()
returnstrue
if an element has the given attribute orfalse
otherwisehasAttributes()
returnstrue
if an element has the given attributes orfalse
otherwisehasChildNodes()
returnstrue
if an element has child node orfalse
otherwiseinsertBefore()
adds a child node before the given elementisDefaultNamespace()
returnstrue
if the statednamespaceURI
is the default orfalse
otherwiseisEqualNode()
checks whether two nodes are equalisSameNode()
checks if two nodes are the sameisSupported()
returnstrue
if a given feature is supported on an elementquerySelector()
gets the first element with the given CSS selectorquerySelectorAll()
gets all elements with the given CSS selectorremoveAttribute()
removes an attribute from the given elementremoveAttributeNode()
removes an attribute node from the given elementremoveChild()
removes the first child nodereplaceChild()
replaces a specified child node with anotherremoveEventListener()
removes a specified event handlersetAttribute()
sets the stated attribute to the specified valuesetAttributeNode()
sets the stated attribute nodetoString()
converts an element to a stringitem()
gets a node with the given index in the NodeList
Changing Element Content
If we select an element, we can set the innerHTML
property to set the content of the element. For example, if we have an element
DOM element, then we can write:
element.innerHTML = 'content';
We set the content inside the element and leave the rest unchanged.
Getting Elements
The most convenient way to work with elements is to get them with the methods listed above. The most commonly used ones are getElementById
, getElementsByTagName
, getElementsByClassName
, and querySelector
, querySelectorAll
.
getElementById
getElementById
lets us get an element by its ID, as its name suggested. It doesn’t matter where the element is, the browser will search the DOM until it finds an element with the given ID or returns null
if it doesn’t exist.
We can use it as follows:
<html>
<head>
<title>Hello</title>
</head>
<body>
<p>
Hello <span id='name'>
</span>
</p>
<script>
const nameEl = document.getElementById('name');
nameEl.innerHTML = 'Jane';
</script>
</body>
</html>
In the code above, we get the element with the ID name
and set the content to Jane, so we get “‘Hello Jane” on the screen.
getElementsByTagName
To get all the elements with the given tag name, we use the getElementsByTagName
function to get all the elements with the given tag name.
We can use it as follows:
<html>
<head>
<title>How are You</title>
</head>
<body>
<p>
Hello <span></span>
</p>
<p>
How are you <span></span>?
</p>
<p>
Goodbye <span></span>
</p>
<script>
const spanEls = document.getElementsByTagName('span');
for (let i = 0; i < spanEls.length; i++) {
spanEls[i].innerHTML = 'Jane';
}
</script>
</body>
</html>
In the code above, we get all the span
elements with getElementsByTag
to get all the span
elements.
getElementsByClassName
To get all the elements with the given class name, we use the getElementsByClassName
function.
We can use it as follows:
<html>
<head>
<title>How are You</title>
</head><body>
<p>
Hello <span class='name'>
</span>
</p>
<p>
How are you <span class='name'>
</span>?
</p>
<p>
Goodbye <span class='name'>
</span>
</p>
<script>
const nameEls = document.getElementsByClassName('name');
for (let i = 0; i < nameEls.length; i++) {
nameEls[i].innerHTML = 'Jane';
}
</script>
</body>
</html>
Appending Element to an existing Element
We can create a new element and attach it to an existing element as a child by using the createElement
method and then using the appendChild
method and pass in the element created with createElement
as the argument of the appendChild
function. We can use it like in the following example:
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>
Hello,
</h1>
<ul id='helloList'> </ul> <script>
const names = ['Mary', 'John', 'Jane'];
const helloList = document.getElementById('helloList');
for (let name of names) {
const li = document.createElement('li');
li.innerHTML = name;
helloList.appendChild(li);
}
</script>
</body>
</html>
Removing Elements
We can remove elements with the removeChild
function. This means you have to find the child you want to remove and then get the parent node of that node. Then you can pass in that element object to the removeChild
function to remove it.
Below is an example of this:
<html>
<head>
<title>Remove Items</title>
</head>
<body>
<ul>
<li id='1'>One <button onclick='remove(1)'>
remove
</button></li>
<li id='2'>Two <button onclick='remove(2)'>
remove
</button></li>
<li id='3'>Three <button onclick='remove(3)'>
remove
</button></li>
</ul> <script>
remove = function(id) {
const el = document.getElementById(id);
el.parentNode.removeChild(el);
}
</script>
</body>
</html>
As you can see, we have to get the node we want to remove and then get the parent node of that by using the parentNode
property. Then we call removeChild
on that. There’s no easier way to remove a node directly.
Now that we can create, manipulate, and remove nodes, we can make simple dynamic web pages without too much effort. Manipulating the DOM directly isn’t very sustainable for complex pages because lots of elements change in the DOM, making getting DOM elements directly difficult and error-prone. The DOM tree changes too much, so it’s very fragile if we make complex dynamic websites this way.