The Document Object Model
The Document Object Model (DOM) is a model that represents the HTML elements on a page. JavaScript can access these elements on the web page to manipulate and edit them.
What can you do with the DOM?
The HTML DOM holds all elements as objects which you may call through properties, methods and events. With this, developers are able to change HTML attributes, elements, create HTML events, inject CSS styles, and more through JavaScript.
Additionally, the DOM and JavaScript, allows you to ask the browser about specific features on elements of the page, and tell it how to respond.
HTML DOM Tree
A good way to visualize the HTML DOM is through an inverted tree of elements, attributes, texts and other node types. At the root we have the document itself, which then branches off to the head and body elements.
Node Types of a DOM Tree
As you can see from the tree above, nodes make up our tree. There are four main types of nodes - document, element, attribute and text nodes.
1) Document node
The document node is the root, and is the starting point of all elements. All other nodes start at the document node.
2) Element nodes
Element nodes are the HTML tags that act as the backbone to the page. When viewing a page's HTML source, this includes all HTML tags embedded within brackets (<>
).
3) Attribute nodes
HTML elements can have attributes. For example, in the <a href="http://google.com">Google</a>
element, the attribute is the href
value. Other common attributes include class
and id
, which can be changed to trigger new rules.
One important aspect of attribute nodes is that they are not children of the elements that contain them. If you look back at the diagram, notice that the attribute nodes are on the side of their elements, not below.
4) Text nodes
Text nodes are children of elements that contain text. Text nodes do not include other elements, so if there exists an element within another, it becomes a child of the parent element.
Document properties and models
Here are a list of document properties. In order to call these, use the dot notation with the document object (eg. document.title
).
title
- Title of the document.
lastModified
- Date at which document was last modified.
URL
- URL of current document.
domain
- The domain of the current document.
write()
- Write text to the document.
getElementById()
- Obtain the element by the id attribute.
querySelectAll()
- List all elements that match a CSS selector query.
createElement()
- Create a new element.
createTextNode()
- Create a new text node.
Retrieving a single element and DOM traversal
When selecting elements from the DOM, we can either select one or many nodes. Let's start with retrieving a single element.
To retrieve an element, we use DOM queries. These are the methods used through JavaScript that we can use to find elements on the DOM tree. Oftentimes, the elements we select are stored into a variable, which serves as a reference to the node; this is known as caching.
getElementById
The most efficient way to obtain an element is through its id
attribute. We may do this with the getElementById()
method, in which we simply pass in the name of the id
. Since we know that no two elements can share the same id
, we are ensured that the browser terminates right after finding the first id
, resulting in quickness and responsivity.
var firstItem = document.getElementById('first')
This command will store the reference to the element with an id
of first
within the firstItem
variable.
querySelector
Another way to select just one element is through a query selector. Given a CSS selector, this returns only the first matched item.
firstParagraph = document.querySelector('p') # First tag.
document.querySelector('.item') # First element with a class "item"
Traversing the DOM - single elements
Once we have selected a single element, we may access the nodes around it through these properties:
parent
- Select parent of current node.
previousSibling
- Select the previous sibling node.
nextSibling
- Select the next sibling node.
firstChild
- Select the first child of current element.
lastChild
- Select last child of current element.
Selecting multiple elements NodeLists
Selecting on element at a time is great for when you want to add a simple interactive feature, but many times you'll want to manipulate multiple elements. There are a few methods that we may use to select multiple elements, which we will see here.
NodeLists
The objects that act as a container to hold several node references are known as NodeLists. There are two types of NodeLists: live and static.
Live vs. Static
One thing we should mention before we begin is whether the NodeList is live or static. In a live NodeList, elements within the NodeList are updated, as scripts are run. A NodeList that is static does not change even after elements are updated on the DOM.
3 ways to access NodeLists
Note that if a method can return a NodeList, it always will. Even if it returns just one item, it is to be treated as a NodeList of size one. Let's now look at the three ways we can obtain a nodelist.
1) Getting elements by class
Using the querySelector()
function, we were only able to select the very first element it approached. To access all the elements of a certain class, we use getElementsByClassName()
.
var allItems = getElementsByClassName('item')
2) Selecting elements by tag
Another way to perform a similar function as above is to select an element by its HTML tag. For example, if you were to select all list elements <li>
:
var allListItems = getElementsByTagName('li')
3) Getting elements matching a CSS selector
To obtain even more power and flexibility, we can use the querySelectorAll()
function, which matches elements that match a CSS selector query. This method returns a static NodeList. The following selects all links that are external (or exit the domain).
querySelectorAll('a[href*="http://"]')
Traversing the DOM - multiple elements
Another way we may traverse the DOM list is by getting all child nodes of a certain element. We may access an element's child nodes through its childNode
property.
var list = querySelector('ol')
var orderedListItems = list.childNodes
Here, orderedListItems
will always be a NodeList.
Handling NodeList
Let's now learn how to handle a NodeList. Recall that NodeLists are a type of collection - a special object that has array-like syntax but object-like capabilities.
Accessing each node
There are two ways we can access a node within a NodeList - the array-like and the object-like way. Since NodeLists use a zero-based index, we are choosing the first item in this example:
myNodeList[0]
myNodeList.item(0)
Try accessing through the array method, as this is easier to type out, and faster to process.
You can also use the firstItem property, which has the same function as above.
Looping through
Oftentimes you'll want to loop through all the nodes and apply some property to everything. Since we can access each node with its index and know the NodeList's length, we may access and apply a function to all elements.
for (var i = 0; i < myNodeList.length; i++)
// Apply things here.
myNodeList.item(i)
Shortcuts to grabbing multiple elements
anchors
- All
<a>
elements with a name attribute. forms
- All the form elements within a document.
images
- All
<img>
elements links
- All link elements with an href attribute.
Modifying Text and Attributes Fields
Let's now talk about accessing and updating text nodes and attribute fields.
Accessing and updating text nodes
First we must select the element that contains the particular text node we want to edit. We can store its reference into a variable, and use the firstChild
property to access its text element. Any text within any of our element's children will not be included.
nodeValue
The text of the text node can be accessed using its only property, nodeValue
. Through this variable, we may access or update the text node.
var item = querySelector('li');
itemText = item.firstChild;
itemText.nodeValue;
The nodeValue
property simply returns the content of the node.
innerHTML
Another approach is the use innerHTML
, which obtains all the text and markup inside of an element. This will access all child elements and the text content within. innerHTML
should not be used, as it is not considered a standard by the W3C.
textContent
The standard way to accessing text is through the textContent
variable.
Setting this node will remove all child elements within, and replace it with the given text.
Using textContent
is more powerful than innerHTML
, since HTML elements are not parsed; this allows you to to write HTML character within an element.
Accessing and updating attributes
As you should recall, attributes are the properties given to an HTML element. For example, the anchor tag (<a href=""></a>
) should always have an href
attribute. Let's now look at the methods that are used to access, modify and update these attributes.
hasAttribute(a)
- True if the element contains the attribute
a
, otherwise False. getAttribute(a)
- Return value of the attribute
a
. setAttribute(a, b)
- Set the attribute value
a
tob
. removeAttribute(a)
- Removes the
a
attribute from the element.
Creating and Deleting Elements
We've looked at how to access the current elements on the DOM, so now let's learn how to create and delete them.
Creating Elements
To create an element, use the createElement()
method, which takes in an element type. We then store this reference into a variable, and use the methods we learned in the previous lessons to add attributes and text nodes.
var newElement = document.createElement("p");
body.appendChild(newElement);
body.newElement.removeChild(newElement);
You have now created your first element from JavaScript! Now let's add it to the DOM so it renders on the page.
Setting attributes
To set attributes to our newly created element Now we can just set the ID.
newElement.setAttribute("class", "body-text")
Creating a text node
We may also create a text node by using the createTextNode()
method. Simply attach this node to our element.
var myTextNode = document.createTextNode("text here");
newElement.appendChild(myTextNode);
Adding the element to the DOM
To append the element to the DOM, we use the appendChild()
method. This takes in the variable that holds a reference to your newly created element. You can then attach it to any pre-exiting element.
Deleting elements
To remove a node, simply use the removeChild()
method.
var elementRemoval = document.getElementById("removeMe");
document.body.removeChild(elementRemoval);