How to REALLY Learn JavaScript Series: Part 5 The DOM

The DOM or Document Object Model represents an API (application programming interface) for HTML documents. The DOM consists of a hierarchal tree of nodes which allow developers to traverse and alter with JavaScript. This post will discuss what the DOM is and why it’s vital to understand for any good web developer.

The DOM

Think of the DOM as the outline of a web page or HTML document. Each element you see in the page is part of the DOM. Each element is commonly referred to as a node with you can access with both CSS and JavaScript based on the type of declaration you provide in your code.

There are several types of nodes within the DOM which you are probably familiar with if you’ve ever written an HTML document in your lifetime (I hope you have if you’re reading this). Each node type has different characteristics, data, and methods. Each have relationships with other nodes. These relations are what create the DOM hierarchy as show here:

dom | web-crunch.com
An outline view of a simple DOM

A simple HTML document looks like below

<html>
  <head>My Website</head>
  <body>
    <p>Hi World!</p>
  </body>
</html>

Every element seen above is a node. Where the HTML element begins and ends is considered a single node. With JavaScript you can modify nodes that already exist or target them with CSS if you need to style them separately.

Node Types

As I noted before, node types vary based on the location, characteristics and data as provided in the HTML document. Some node types include:

  • Elements
  • Attributes
  • Text
  • Entities
  • Document
  • Document Type

I’ve only broken the surface on the types but you can find more if you inspect the element in your browser of choice. A neat way to find out more about a particular node is to log it through the console. Inside of Chrome (my browser of choice) you can do a console.log(myVariable) of any type of node to find out more about it. If you set a variable to find say the body element like so:

var body = document.querySelector('body');
console.log($(body));

Keep in mind that I’m using jQuery here to spit out the all the parameters it returns which look like this:

console | web-crunch.com

After returning the log of the body node we can investigate all types of parameters associated with it. You can target much of this data with JavaScript if you like.

Node Relationships and Manipulation

Most elements or nodes within an HTML document are related in some way. The code you write is typically contained inside some other element and ultimately the <html> element. Relationships are described in terms of traditional family relationships like parents or children and even siblings. You can think of the DOM as a different kind of family tree if you so please. A parent node will have siblings called children or childs. Each sibling can interact with the other or the parent again using JavaScript. Selecting nodes based on their relationship is common within jQuery.

Manipulate

You can add, edit or delete nodes from the HTML document using JavaScript. This theorem is similar to the C.R.U.D. model used in many applications or database platforms if you have ever heard of it. Saving these elements so they exist the next time you visit the page is also possible but I’ll save that for a later article. The most common way to add a node is to append a child by using the appendChild() method. This adds a node to the end of a childNodes list. Doing this updates all relationships within the DOM automatically. Here’s a quick example:

var myNode = anotherNode.appendChild(newNode);
alert(myNode == newNode); // true
alert(anotherNode.lastChild == newNode); //true

If a node passed into appendChild() is already part of the document, it is removed and added wherever you told it to be.

Other methods

Some other methods to manipulate the DOM are

Selectors

You may be asking yourself, “Ok, I get what nodes are and the DOM but how do I access it or modify nodes with JavaScript?”. Lucky for you JavaScript has a selector API which gives you access to pretty much any node within an HTML document. Similar to styling elements with CSS you can traverse the DOM with JavaScript to find specific elements based on their declaration.

To gain access to the <body> element for example you would write a bit of javascript like this:

var body = document.querySelector('body')

To help with speed it’s a common trend to use id’s on elements you need to directly select with JavaScript. Doing so results in a bit of HTML like this:

<html>
  <head>
   <title>My Document</title>
  </head>
  <body>
    <header class="home">
     <nav id="navigation">
       <ul>
         <li class="first-link"><a href="#">Home</a></li>
         <li><a href="#">About</a></li>
         <li><a href="#">Projects</a></li>
         <li><a href="#">Contact</a></li>
       </ul>
     </nav>
    </header>
  </body> 
</html>

The main advantage to doing this is speed. If you have many of the same type of elements on a page or have a larger document more times than not when you don’t use an id your code will take a bit longer to execute do to the fact that it has to search the whole document to find what it is you were targeting. Using an id speeds this up because the DOM is read from top to bottom. Once an id is found the rendering engine will stop because it was successful.

To target a specific id within your HTML document you can use a different type of query selector which you may have seen me use in previous posts in this series.

var nav = document.getElementById('navigation');

Targeting classes is basically the same thing as Id’s only the JavaScript is a tiny bit different. Selecting a class would like like this:

var header = document.querySelector('home');

You can even select elements with a specific class to make things more explicit:

var firstNavLink = document.querySelector('home.first-link');

Selecting all of one type of element is achieved by using the querySelectorAll() method. Doing this selects all the <p> tags in the HTML below:

<html>
  <head>
   <title>QuerySelectorAll</title>
  </head>
  <body>
    <div class="container">
      <p>This is some text</p>
      <p>This is some text again</p>
    </div>
    <div class="container">
      <p>Look more text</p>
      <p>Awesome another line of text.</p>
  </div>
</body>
</html>

The javascript used to select all the <p> tags looks like this:

var paragraphs = document.querySelectorAll('p');

This as you would guess selects every <p> tag within the document.

HTML5 To the Rescue

HTML5 has changed the way we author web pages. The specification contains a large amount of JavaScript APIs designed for use with markup additions found in the new version of the language. Part of these APIs overlay with the DOM structure and provide extensions that browsers should already provide.

The most popular addition is the new getElementsByClassName() method. This method accepts a single argument, which as you would probably have guessed, is a class you may have used multiple times within your HTML document.

// gets all active classes within the DOM
var activeStates = getElementsByClassName("active");

classList
HTML5 introduces a new way to manipulate class names in side a DOM element node. Say for example you have a div with the classes like below:

<div class="default btn btn-primary"></div>

The old way (before HTML5) to manipulate (in this case remove) the classes within this node is to split the node of all it’s class names, find the class to remove, actually remove the class name, and then set back the classes from before. With that you end up with roughly 15 – 20 lines of JavaScript. HTML5 brings us new methods that attach to the classList method. This ideal is very similar to chaining in jQuery.

The additional methods include:

  • add(value) – adds the given string to the list. If the value already exists then JavaScript knows not to add it.
  • contains(value) – A boolean type of method that indicates if the given method exists or not
  • remove(value) – Removes the given string from the classList
  • toggle(value) – Toggles the value. It it already exists it is removed. If it doesn’t exist it is added.

Some examples of these methods in action:

// adds "active" class
div.classList.add('active'); 

// remove the "user" class
div.classList.remove('user'); 

// toggle the "user" class
div.classList.toggle('user')

A more advanced example with the HTML looking something like this:

<html>
  <head>
   <title>My App Page</title>
  </head>
  <body>
   <div id="myapp" class="module welcome">
      <p>Welcome User!</p> 
   </div>
  </body>
</html>

And the JavaScript could be something like this:

var appName = document.getElementById('myapp');

if (appName.classList.contains("welcome") && !appName.classList.contains("hidden")) {
 
    for(var i=0, len=appName.className.length; i < len; i++) {
      doSomething(appName.classList[i]);
    }
  
};

Here I’m querying the DOM to get the id of a div I created which also has two classes module and welcome and assigning it to a variable called appName. From there I wrote an if statement that tests to see if the class contains welcome and doesn’t contain the class hidden. If all returns true then I wrote a loop that iteratees each class name within my appName div.

Changing the HTML Document

HTML5 extends it’s document property to allow more functionality than every version before it. Some browsers have supported this functionality for a while now but the features are still new to the web world.

readyState
readyState isn’t anything new but now in HTML5 it has been retouched. There are two properties to go along with readyState. Those are:

  • loading – The document is loading
  • complete – The document has completed loading

You can use the readyState property, and most likely will use the readyState property to do something once fired. If the document has finished loading you can trigger something new to happen thanks to the readyState method.

if (document.readyState == "complete") {
    alert('Your fully loaded brah!');
};

Custom Data Attributes
You may have seen some HTML with random attributes assigned to them like data-role or data-name. These are typically only used for targeting with JavaScript. custom data attributes can be called whatever you like, much like a class name or id. The only catch is the data- much prefix whatever your name may be.

<div id="module1" class="module" data-modId="1" data-modName="mediaModule"></div>

When a custom data attribute is defined, it can be access using the dataset property of the element.

var mod1 = document.getElementById('module1');

// set new values
mod1.dataset.modId = 2;
mod1.dataset.modName = "Events";

// Does the modName value exist?
if (mod1.dataset.modName) {
  alert('Yes');
}

innerHTML
If you’ve ever wanted to insert HTML using JavaScript you would use the innerHTML extension.

// simple text output
var div = document.querySelector('div');
div.innerHTML = "Hello World";

// html output
var para = document.querySelector('p');
para.innerHTML = "<p> This is a paragraph </p>";
// When passing HTML, be sure to escape the characters so the full code renders. 
// my syntax highlighter on here is keeping me from showing you this
// Sorry :)

Commonly-used interfaces inside the DOM

The document and window objects are what you will make the most use of generally speaking. The window object refers to the browser in most cases and the document object grants you access to the root document itself. Another commonly used interface is the Element property which inherits from the Node interface. These two interfaces provide you with more control to the DOM and have specific methods and properties for doing so. Some of the most common are listed below (complete credit to the Mozilla Docs for this list):

  • document.getElementById(id)
  • element.getElementByTagName(name)
  • document.createElement(name)
  • parentNode.appendChild(node)
  • element.innerHTML
  • element.style.left
  • element.setAttribute
  • element.getAttribute
  • element.addEventListener
  • window.content
  • window.onload
  • window.dump
  • window.scrollTo

Extending further

HTML5 provides a large number of extensions to the standard DOM which explains all the hype over the years. Some extensions include:

Final Words

The DOM as a whole is used in regards to any language used for the web. We write HTML to establish DOM nodes, we use CSS to target specific nodes to stylize their appearance, and finally we use JavaScript to provide interactivity within the DOM whether it be through DOM level manipulation, adding or removing elements, or updating content without a page refresh. It’s important to understand how the family tree like structure works inside the DOM. Being very familiar with this will make you a better developer for years to come.

The Series So Far