The Window object has a document property, which is reference to a Document object and is also available as a global variable. The Document object represents the content of the window and is the main object of Document Object Model.
Document Object Model (DOM) is an application programming interface (API) for HTML documents. The DOM represents a HTML document as a tree structure of objects. Each node represents an element in the document. Elements of the document can be added, removed and modified.
Document Structure
HTML document can be treated as a tree of nodes. Consider the following HTML document:
<!DOCTYPE html> <html> <head> <title>Page meta title</title> </head> <body> <h1>Main header</h1> <p>First paragraph</p> <div><span>Part of text</span></div> </body> </html>
The DOM representation of this HTML document is as follows:
Each HTML tag is treated as a node of the tree. Each node in the tree is represented by a Node object. The root is the Document node, that represents the entire document. HTML elements (like <head>, <body>, <div>, etc) are represented by Element nodes, texts are represented by Text nodes, comments by Comment nodes, etc. The Node is the most generic type. Its subtypes represent specific types of HTML elements. Figure below presents hierarchy tree of nodes:
Nodes and Tree Traversals
Structure of the HTML document is like tree of Node objects. The Node object type defines properties that contain information about the node and the relationship between nodes.
- The nodeType property specify the node type of HTML element. Its value can be a number from 1 to 12. Below the list of current node types and their values:
Node.ELEMENT_NODE (1)
Node.TEXT_NODE (3)
Node.PROCESSING_INSTRUCTION_NODE (7)
Node.COMMENT_NODE (8)
Node.DOCUMENT_NODE (9)
Node.DOCUMENT_TYPE_NODE (10)
Node.DOCUMENT_FRAGMENT_NODE (11)
- The nodeValue property holds the content of Text nodes.
- The nodeName property holds tag name of an element.
The properties that allow to traverse tree of nodes are as follows:
- The parentNode specifies parent node of current one.
- The childNodes holds the list of child nodes as a NodeList object.
- The firstChild specifies the first child of a node.
- The lastChild specifies the last child of a node.
- The nextSibling specifies the next sibling of a node. Siblings are nodes with the same parent.
- The previosSiblin specifies the previous sibling.
Assuming that myNode is a node in the tree representing a selected element you can find other associated nodes and traverse the tree:
// get parent node of myNode myNode.parentNode; // get first child of myNode myNode.firstChild; //get second child of myNode myNode.childNodes[1]; //get next sibling of myNode myNode.nextSibling; // get second sibling of myNode if (myNode.nextSibling) { myNode.nextSibling.nextSibling; }
Selecting Document Elements
Elements of the document can be read and modified. In order to do this, first you have to select the element. The DOM provides several ways to obtain an element.
Selecting element by ID
Every HTML element can have an id attribute, which should be unique in the document.
<div id="quantity">10</div>
You can select an element using its unique ID with the getElementById() method of the Document object type. This method returns Element object.
var quantityElement = document.getElementById("quantity");
Selecting elements by name
HTML elements can have a name attribute, usually used by form elements. The value of a name attribute do not have to be unique.
<input type="radio" name="pet" value="cat"> Cat<br> <input type="radio" name="pet" value="dog"> Dog
You can select all elements with specific name using the getElementByName() method of the HTMLDocument object type. This method returns NodeList object, which is like a read-only array of Element objects. It is available only for HTML documents (not XML documents).
var petsList = document.getElementsByName('pet');
Setting the name attribute for some HTML elements like <form>, <img>, <object>, <embed>, <iframe> automatically creates properties with those names in the Document object. If there is only one element with a specific name, the value of a related property is this element. If there is more elements, then the value of the property is NodeList object.
<form name="contactForm">
var contactForm = document.contactForm;
Selecting elements by tag type
HTML elements can be selected by their tag type using getElementsByTagName() method of the Document object type. This method returns a NodeList object containing found elements in the order in which they appear in the document.
<img src="img1.jpg"> <br> <img src="img2.jpg">
var imagesList = document.getElementsByTagName('img');
For certain types of HTML elements like <form>, <img>, <a> HTMLDocument defines properties (forms, images, links) which allow easy access to these elements. These properties return HTMLCollection object which is similar to NodeList.
var imagesList = document.images;
Important thing about NodeList and HTMLCollection is that returned objects are dynamic. It means that they update NodeList or HTMLCollection of elements when the document changes.
Selecting elements by CSS class
HTML elements can have class attribute through which you can specify CSS classes, which define presentation styles. HTML elements store value of class attribute in the className property. To select all elements with a given class or classes use getElementsByClassName() method and specify required classes separated by space. It returns NodeList object.
<div class="content">Content 1</div> <p class="content">Content 2</p>
var contentList = document.getElementsByClassName('content');
Selectors API
In addition to previously discussed methods of selecting elements W3C defines The Selectors API, which allows you to find elements that match a specific CSS selector. The most important are two methods: querySelectorAll() and querySelector(). The difference between them is that the former returns all matched elements and the latter returns only the first matched element. Both these methods are available on the Document, the Element and the DocumentFragment object types.
The querySelectorAll() method accepts CSS query as an argument and returns NodeList object with all matched elements.
Unlike previously discussed methods, returned NodeList objects by Selectors API methods are static. It means that they do not update when the document changes.
// select all elements in the document with CSS class "item" var itemsList = document.querySelectorAll('.item'); // select all paragraph elements in the document with CSS class "note" var notesList = document.querySelectorAll('p.note'); // inside an element with a "content" id select all elements with CSS class "post" document.getElementById('content').querySelectorAll('.post')
The querySelector() method also accepts CSS query as an argument and returns the first matched element.
// inside the element with a "menu" id select the first link with CSS class "internal" nested in the span tag document.getElementById('menu').querySelector('span a.internal')
Element Content
Element content can be considered as HTML, plain text or Text Nodes.
HTML content
The Element has the innerHTML property which holds the content of that element. You can use the innerHtml property to read content of an element as well as to write a new content.
<p id="note">A small <b>portion</b> of the content.</p>
// returns: "A small <b>portion</b> of the content." var htmlContent = document.getElementById('note').innerHTML; // result: "<p id="note">A new <i>portion</i> of the content!</p>" document.getElementById('note').innerHTML = 'A new <i>portion</i> of the content!';
The element has also the outerHTML property. It holds the content of the element together with the surrounding opening and closing tags of that element. When you assign new content to outerHTML property, you replace the element itself.
<p id="note">A small <b>portion</b> of the content.</p>
// returns "<p id="note">A small <b>portion</b> of the content.</p>" var htmlContent = document.getElementById('note').outerHTML; // result: "<div>A new <i>portion</i> of the content!</div>" document.getElementById('note').outerHTML = '<div>A new <i>portion</i> of the content!</div>';
Plain text content
Another option is to read or write element’s content as a plain text. You can do this using the textContent property of an Element.
<p id="note">A small <b>portion</b> of the content.</p>
// returns: "A small portion of the content." document.getElementById('note').textContent; // assigns: "A new content." document.getElementById('note').textContent = "A new content.";
Text Nodes content
Third possibility to deal with the content of an element is to use its child text nodes. In text nodes the content is holded in the nodeValue property.
<p id="note">A simple content.</p>
var content = ''; var childNode = document.getElementById('note').firstChild; if (childNode != null && childNode.nodeType == Node.TEXT_NODE) { content = childNode.nodeValue; } console.log(content); // A simple content.
Creating and manipulating Nodes
In addition to changing the content of elements, it is also possible to modify the document at the node level.
Creating Nodes
To create a new Element node you can use the createElement() method of the Document object type. It accepts the name of the tag element as an argument.
var elementNode = document.createElement('p');
Similarly, to create a new Text node you can use the createTextNode method. It accepts a string content as an argument.
var textNode = document.createTextNode('Text node content');
Inserting Nodes
A newly created node is not automatically added into the document. You can use appendChild() or insertBefore() methods of the Node object type to insert a node into the document.
The appendChild() inserts a node passed as an argument as the last child of the element on which it is invoked.
An example:
<div id="container"><span>Text...</span></div>
var spanNode = document.createElement('span'); var textNode = document.createTextNode('Another text'); spanNode.appendChild(textNode); var divNode = document.getElementById('container'); divNode.appendChild(spanNode); // result: // <div id="container"><span>Text...</span><span>Another text</span></div>
The insertBefore() method is similar to the appendChild(). It also inserts a node passed as the first argument as a child of the element on which it is invoked. However the second argument allows you to specify before which child node given node is to be inserted. If the second argument is null, the node is inserted as a last child.
An example:
<div id="container"><span>Text...</span></div>
var spanNode = document.createElement('span'); var textNode = document.createTextNode('Another text 2'); spanNode.insertBefore(textNode, null); var divNode = document.getElementById('container'); var firstChild = divNode.firstChild; divNode.insertBefore(spanNode, firstChild); // result: // <div id="container"><span>Another text 2</span><span>Text...</span></div>
The appendChild() and the insertBefore() can be used not only to insert new nodes but also to change location of a node in the document. If you call one of these methods to insert a node that is already in the document, it will be removed from previous place and insert to a new one.
Replacing Nodes
It is possible to replace one node by an another. The replaceChild() method replaces a child node by a new node. A new node is accepted as the first argument and a node to be replaced as the second argument. This method is invoked on the parent node of the node to be replaced.
An example:
<h3><div id="container"><span>Text 1</span><span>Text 2</span></div></h3>
var divNode = document.getElementById('container'); var lastChild = divNode.lastChild; var textNode = document.createTextNode('Alternative text'); divNode.replaceChild(textNode, lastChild); // Result: // <div id="container"><span>Text 1</span>Alternative text</div>
Removing Nodes
To simply remove a node use removeChild() method. I accepts a node to be removed as the argument and it is invoked on the parent node of the node to be removed.
An example:
<div id="container"><span>Text 1</span>Alternative text</div>
var divNode = document.getElementById('container'); divNode.removeChild(divNode.firstChild); // Result: // <div id="container">Alternative text</div>
Attributes
HTML elements in addition to tag name can have attributes that are name-value pairs.
You can read and write values of these attributes thru properties of HTMLElement object type. HTMLElement object type that represents elements in the HTML document specifies properties that reflect the standard attributes of HTML elements. It includes general purpose attributes (such as id, title), element-specific attributes (src, href, action), event-handler attributes (onclick). Property names are case sensitive.
Some HTML attribute names are reserved words in JavaScript. That is why properties that represent these attributes have amended name (className for class attribute, htmlFor for for attribute).
An example:
<img src="image1.jpg" alt="image"> <a href="http://www.example.net" class="myLink">www.example.net</a>
var image = document.images[0]; // set element id to myImg image.id = 'myImg'; // replace image1.jpg to image2.jpg image.src = 'image2.jpg'; var link = document.links[0] // read URL of the link var url = link.href; // read CSS class of the link var cssClass = link.className;
Values stored in properties are the same type as mirrored attribute (usually string, but also may be number or boolean).
The Element object type defines methods getAttribute() and setAttribute() that allow you to read and set HTML attributes. These methods also allow you to deal with non-standard HTML attributes. The getAttribute() method accepts as the argument name of the attribute and it returns always a value of string type. The setAttribute() method accepts as the first argument name of attribute and as the second argument a value to be set. Attributes names are case insensitive.
An example:
<img src="image1.jpg" alt="image" id="myImg" height="30">
// read height attribute var height = document.getElementById('myImg').getAttribute('HEIGHT'); // set CSS class smallImg document.getElementById('myImg').setAttribute('class', 'smallImg');
The removeAttribute() method of Element object type allows you to delete a given attribute from the element. Using the hasAttribute() method you can check if an attribute exists in a given element.
An example:
<input type="text" value="" disabled="disabled" id="myField">
document.getElementById('myField').removeAttribute('disabled'); // it returns false: document.getElementById('myField').hasAttribute('disabled');
In order to HTML document was valid, non-standard HTML attributes has to begin with “data-” prefix. For example instead of attribute name “category” should be “data-category”. The Element object type defines a dataset property that holds values of attributes with “data-” prefix.
An example:
<div id="myDiv" data-category="training">Content...</div>
var category = document.getElementById('myDiv').dataset.category; // training
Writing in the document
Document object type provides the write() method that allows you to write in the document. There is also writeln() method which is like the write() except that it appends a new line character (n) at the end of the output string. These methods can be used to dynamically insert content when page is being loaded.
<!DOCTYPE html> <html> <head> <title>The document.write() while the page is being loaded</title> </head> <body> <div>Current time: <script> document.write('<span id="time" style="font-weight: bold;">' + (new Date()) + '</span>'); </script> </div> </body> </html>
HTML code added thru the write() method is treated the same as if it was included directly in the document and can be accessed through DOM API.
The write() method can be used to output the content into the document only while the document is being loaded. If the write() method is used after the document has been loaded, it erases and overwrites the current document.
<!DOCTYPE html> <html> <head> <title>The document.write() after the page has been loaded</title> </head> <body> <div>This text won't be visible! <script> window.onload = function(){ document.write('This text overwrites the entire page content.'); }; </script> </div> </body> </html>
The document.write() method is one of the oldest API’s in JavaScript and currently it is rarely used. There are better solutions to add content to the document like the innerHTML property.
Reply