The HTML DOM (Document Object Model)
Basic DOM Knowledge+
What is DOM - MDN
When a web page is loaded, the browser creates a Document Object Model of the page.
The W3C DOM standard is separated into 3 different parts:
- Core DOM - standard model for all document types
- XML DOM - standard model for XML documents
- HTML DOM - standard model for HTML documents
The HTML DOM is a standard for how to get, change, add, or delete HTML elements.
Query Selectors
element
.querySelector(selector
) returns reference to the first match ofselector
element
.querySelectorAll(selectors
) returns a “nodelist” containing references to all of the matches of theselectors
It’s important to note that when using querySelectorAll, the return value is not an array. It looks like an array, and it somewhat acts like an array, but it’s really a “nodelist”. The big distinction is that several array methods are missing from nodelists. One solution, if problems arise, is to convert the nodelist into an array. You can do this with Array.from() or the spread operator.
Some examples below:
<p id="p2">Hello World!</p> <script> document.querySelector("#p2").style.color = "blue"; document.querySelector("#p2").style.fontFamily = "Arial"; document.querySelector("#p2").style.fontSize = "larger"; document.querySelector("#p2").style.backgroundColor = "orange"; document.querySelector("#p2").innerHTML = "This text will replace the text of id P2"; </script>
An HTMLCollection/NodeList is NOT an array!
An HTMLCollection may look like an array, but it is not.
You can loop through the list and refer to the elements with a number (just like an array).
However, you cannot use array methods like valueOf(), pop(), push(), or join() on an HTMLCollection.
The Difference Between an HTMLCollection and a NodeList
An HTMLCollection is a collection of HTML elements.
A NodeList is a collection of document nodes.
In many cases this very much be the same thing.
Both an HTMLCollection object and a NodeList object is an array-like list (collection) of objects.
Both have a length property defining the number of items in the list (collection).
Both provide an index (0, 1, 2, 3, 4, ...) to access each item like an array.
HTMLCollection items can be accessed by their name, id, or index number.
NodeList items can only be accessed by their index number.
Only the NodeList object can contain attribute nodes and text nodes.
Collections are iterable using for..of. Sometimes people try to use for..in for that.
Learning Outcomes
What is DOM in relation to a webpage?
- The Document Object Model is a tree-like representation of the contents on a webpage or document.
What's the difference between a "node" and an "element"?
- A "node" is any object in the DOM hierarchy while an "element" is one specific node.
- "Nodes" can include elements, text content inside an element, code comment blocks not visible to the user, the document itself and even abstract types like "fragments".
How do you target nodes with "selectors"?
- There are several ways, with CSS style-selectors, to target a node.
<div class="display"></div>
can be selected as follows:div
div.display
.display
- There are also relational selectors such as
firstChild
orlastSibling
. - Combined with "Query Selectors", this is how you can target a node using JavaScript
- i.e.
document.querySelector(".display");
would select the div above.What are the basic methods for finding/adding/removing and altering DOM nodes?
- As mentioned above, you can find nodes in the DOM using query selectors.
- To create an element, use
document.createElement(tagName[, options])
- i.e.
const div = document.createElement('div');
will create a div element. However, this div has not been added to the webpage yet. - To append this element, use
parentNode.appendChild(childNode)
- i.e.
parentNode.appendChild(div);
- To remove this element, parentNode.removeChild(child)
- This will remove child from parentNode on the DOM and returns reference to child.
- i.e.
parentNode.removeChild(div);
- Once you have a reference to an element, as above, you can alter it in many ways.
div.style.color = 'blue';
adds the indicated style rulediv.setAttribute('id', 'theDiv');
sets the id attribute of our div totheDiv
.
What is the difference between a "nodelist" and an "array of nodes"?
- A "nodelist" looks like an array, but it is missing several methods that come with an Array.
- A solution to this problem is to use the spread operator or Array.from() to convert a nodelist into an array.
How do "events" and "listeners" work? What are three ways to use events in your code?
- "Events" are how you make your webpage dynamic. They are triggered by "listeners", and can fire when the page loads, when you click your mouse, when you push keys on your keyboard, and many, many more.
- The three primary ways to use events are:
- By attaching scripts to event attributes on elements in the HTML document.
<button onclick="alert(this.tagName)">Click Me</button>
- By setting the "on_event_" property on the DOM object in your JavaScript.
- By attaching event listeners to the nodes in your JavaScript.
// the html file
<button id="btn">Click Me</button>
// the JavaScript file
var btn = document.querySelector(‘#btn’);
btn.onclick = (e) => alert(e.target.tagName);
// the html file
<button id="btn">Click Me Too</button>
// the JavaScript file
var btn = document.querySelector('#btn');
btn.addEventListener(‘click’, (e) => {
alert(e.target.tagName);
});
How does "bubbling" work?
- Bubbling is a form of "event propagation."
- It is an efficient method for firing an event on multiple elements -- starting from the innermost element -- and "bubbling" up to outer elements.
Various type of Node:
- Element node: An element, as it exists in the DOM.
- Root node: The top node in the tree, which in the case of HTML is always the
HTML
node (other markup vocabularies like SVG and custom XML will have different root elements). - Child node: A node directly inside another node. For example,
IMG
is a child ofSECTION
in the above example. - Descendant node: A node anywhere inside another node. For example,
IMG
is a child ofSECTION
in the above example, and it is also a descendant.IMG
is not a child ofBODY
, as it is two levels below it in the tree, but it is a descendant ofBODY
. - Parent node: A node which has another node inside it. For example,
BODY
is the parent node ofSECTION
in the above example. - Sibling nodes: Nodes that sit on the same level in the DOM tree. For example,
IMG
andP
are siblings in the above example. - Text node: A node containing a text string.
The HTML DOM NodeList Object
<p>Hello World!</p> <p>Hello Norway!</p> <p id="demo"></p> <script> var myNodelist = document.querySelectorAll("p"); document.getElementById("demo").innerHTML = "The innerHTML of the second paragraph is: " + myNodelist[1].innerHTML; </script>
HTML DOM Node List Length
The length
property defines the number of nodes in a node list:
<p>Hellow World!</p> <p>Hellow Norway!</p> <p id="demo"></p> <script> var myNodelist = document.querySelectorAll("p"); document.getElementById("demo").innerHTML = "This document contains " + myNodelist.length + " paragraphs."; // 3 </script>
function myFunction() { var myNodelist = document.querySelectorAll("p"); var i; for (i = 0; i < myNodelist.length; i++) { myNodelist[i].style.color = "red"; } }
NodeList - MDN
Node Properties & Methods+
Node Properties
Node.baseURI
Read only- Returns a
DOMString
representing the base URL. The concept of base URL changes from one language to another; in HTML, it corresponds to the protocol, the domain name and the directory structure, that is all until the last'/'
. Node.baseURIObject
- (Not available to web content.) The read-only
nsIURI
object representing the base URI for the element. Node.childNodes
Read only- Returns a live
NodeList
containing all the children of this node.NodeList
being live means that if the children of theNode
change, theNodeList
object is automatically updated. Node.firstChild
Read only- Returns a
Node
representing the first direct child node of the node, ornull
if the node has no child. Node.isConnected
Read only- Returns a boolean indicating whether or not the Node is connected (directly or indirectly) to the context object, e.g. the
Document
object in the case of the normal DOM, or theShadowRoot
in the case of a shadow DOM. Node.lastChild
Read only- Returns a
Node
representing the last direct child node of the node, ornull
if the node has no child. Node.nextSibling
Read only- Returns a
Node
representing the next node in the tree, ornull
if there isn't such node. Node.nodeName
Read only- Returns a
DOMString
containing the name of theNode
. The structure of the name will differ with the node type. E.g. AnHTMLElement
will contain the name of the corresponding tag, like'audio'
for anHTMLAudioElement
, aText
node will have the'#text'
string, or aDocument
node will have the'#document'
string. Node.nodeType
Read only- Returns an
unsigned short
representing the type of the node. Possible values are:Name Value ELEMENT_NODE
1
ATTRIBUTE_NODE
2
TEXT_NODE
3
CDATA_SECTION_NODE
4
ENTITY_REFERENCE_NODE
5
ENTITY_NODE
6
PROCESSING_INSTRUCTION_NODE
7
COMMENT_NODE
8
DOCUMENT_NODE
9
DOCUMENT_TYPE_NODE
10
DOCUMENT_FRAGMENT_NODE
11
NOTATION_NODE
12
Node.nodeValue
- Returns / Sets the value of the current node
Node.ownerDocument
Read only- Returns the
Document
that this node belongs to. If the node is itself a document, returnsnull
. Node.parentNode
Read only- Returns a
Node
that is the parent of this node. If there is no such node, like if this node is the top of the tree or if doesn't participate in a tree, this property returnsnull
. Node.parentElement
Read only- Returns an
Element
that is the parent of this node. If the node has no parent, or if that parent is not anElement
, this property returnsnull
. Node.previousSibling
Read only- Returns a
Node
representing the previous node in the tree, ornull
if there isn't such node. Node.textContent
- Returns / Sets the textual content of an element and all its descendants.
Node Methods
Node.appendChild()
- Adds the specified childNode argument as the last child to the current node.
If the argument referenced an existing node on the DOM tree, the node will be detached from its current position and attached at the new position. Node.cloneNode()
- Clone a
Node
, and optionally, all of its contents. By default, it clones the content of the node. Node.compareDocumentPosition()
- Compares the position of the current node against another node in any other document.
Node.contains()
- Returns a
Boolean
value indicating whether a node is a descendant of a given node or not. Node.getRootNode()
- Returns the context object's root which optionally includes the shadow root if it is available.
Node.hasChildNodes()
- Returns a
Boolean
indicating if the element has any child nodes, or not. Node.insertBefore()
- Inserts a
Node
before the reference node as a child of a specified parent node. Node.isDefaultNamespace()
- Accepts a namespace URI as an argument and returns a
Boolean
with a value oftrue
if the namespace is the default namespace on the given node orfalse
if not. Node.isEqualNode()
- Returns a
Boolean
which indicates whether or not two nodes are of the same type and all their defining data points match. Node.isSameNode()
- Returns a
Boolean
value indicating whether or not the two nodes are the same (that is, they reference the same object). Node.lookupPrefix()
- Returns a
DOMString
containing the prefix for a given namespace URI, if present, andnull
if not. When multiple prefixes are possible, the result is implementation-dependent. Node.lookupNamespaceURI()
- Accepts a prefix and returns the namespace URI associated with it on the given node if found (and
null
if not). Supplyingnull
for the prefix will return the default namespace. Node.normalize()
- Clean up all the text nodes under this element (merge adjacent, remove empty).
Node.removeChild()
- Removes a child node from the current element, which must be a child of the current node.
Node.replaceChild()
- Replaces one child
Node
of the current one with the second one given in parameter.
<ul id="list"> <li><a href="link1.html" class="link_one">Link Number One</a></li> <li><a href="link2.html">Link Number Two</a></li> <li><a href="link3.html">Link Number Three</a></li> <li><a href="link4.html">Link Number Four</a></li> </ul>
We can access the first link in our unordered list using any one of the following 3 sections of code:
var myLinkList = document.getElementById("list"); var myFirstLink = myLinkList.childNodes[0].childNodes[0]; alert(myFirstLink.className);
var myLinkList = document.getElementById("list"); var myFirstLink = myLinkList.firstChild.firstChild; alert(myFirstLink.className);
var myLinkList = document.getElementById("list"); var myFirstLink = myLinkList.firstChild.firstChild.nextSibling.previousSibling; alert(myFirstLink.className);
DOM by Mozilla References+
Essential DOM Methods
querySelector() and querySelectorAll()+
querySelector()
The querySelector()
method returns the first element that matches one or more CSS selectors. If no match is found, it returns null.
Before querySelector()
was introduced, developers widely used the getElementById() method which fetches an element with a specified id value.
Although getElementById()
is still a useful method, but with the newer querySelector()
and querySelectorAll()
methods we are free to target elements based on any CSS selector, thus we have more flexibility.
Syntax
var ele = document.querySelector(selector);
- ele – First matching element or null (if no element matches the selectors)
- selector – one or more CSS selectors, such as "#fooId", ".fooClassName", ".class1.class2", or ".class1, .class2"
Selectors can also be really powerful, as demonstrated in the following example. Here, the first <input>
element with the name "login" (<input name="login"/>) located inside a <div>
whose class is "user-panel main" (<div class="user-panel main">) in the document is returned:
var el = document.querySelector("div.user-panel.main input[name='login']");
In this first example, the first <style> element which either has no type or has type "text/css" in the HTML document body is returned:
var el = document.body.querySelector("style[type='text/css'], style:not([type])");
This example demonstrates that the hierarchy of the entire document is considered when applying selectors, so that levels outside the specified baseElement are still considered when locating matches.
<div> <h5>Original content</h5> <p> inside paragraph <span>inside span</span> inside paragraph </p> </div> <div> <h5>Output</h5> <div id="output"></div> </div> <script> var baseElement = document.querySelector("p"); document.getElementById("output").innerHTML = (baseElement.querySelector("div span").innerHTML); </script>
The result looks like this:
Original content inside paragraph inside span inside paragraph Output inside span
querySelectorAll()
Unlike querySelector()
that returns only the first instance of all matching elements,querySelectorAll()
returns all elements that match the specified CSS selector.
The matching elements are returned as a NodeList object that will be an empty object if no matching elements are found.
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
Syntax
var eles = document.querySelectorAll(selector);
- eles – A NodeList object with all matching elements as property values. The object is empty if no matches are found.
- selector – one or more CSS selectors, such as "#fooId", ".fooClassName", ".class1.class2", or ".class1, .class2"
The example below uses the same HTML as the previous one. However, in this example, all paragraphs are selected with querySelectorAll(), and are colored blue.
<p>paragraph one</p> <p>paragraph two</p> <div>div one</div> <p>paragraph three</p> <div>div two</div> var paragraphs = document.querySelectorAll('p'); for(var p of paragraphs) p.style.color = 'blue';
To obtain a NodeList of all of the <p> elements in the document:
var matches = document.querySelectorAll("p");
This example returns a list of all <div> elements within the document with a class of either "note" or "alert":
var matches = document.querySelectorAll("div.note, div.alert");
Here, we get a list of <p>
elements whose immediate parent element is a div with the class "highlighted" and which are located inside a container whose ID is "test"
var container = document.querySelector("#test"); var matches = container.querySelectorAll("div.highlighted > p");
This example uses an attribute selector to return a list of the iframe elements in the document that contain an attribute named "data-src":
var matches = document.querySelectorAll("iframe[data-src]");
Here, an attribute selector is used to return a list of the list items contained within a list whose ID is "userlist" which have a "data-active" attribute whose value is "1":
var container = document.querySelector("#userlist"); var matches = container.querySelectorAll("li[data-active='1']");
Once the NodeList of matching elements is returned, you can examine it just like any array. If the array is empty (that is, its length property is 0), then no matches were found.
Otherwise, you can simply use standard array notation to access the contents of the list. You can use any common looping statement, such as:
var highlightedItems = userList.querySelectorAll(".highlighted"); highlightedItems.forEach(function(userItem) { deleteUser(userItem); });
<div class="outer"> <div class="select"> <div class="inner"> </div> </div> </div> var select = document.querySelector('.select'); var inner = select.querySelectorAll('.outer .inner'); inner.length; // 1, not 0!
In this example, when selecting ".outer .inner" in the context the <div> with the class "select", the element with the class ".inner" is still found, even though .outer is not a descendant of the base element on which the search is performed (".select"). By default, querySelectorAll() only verifies that the last element in the selector is within the search scope.
The :scope pseudo-class restores the expected behavior, only matching selectors on descendants of the base element:
var select = document.querySelector('.select'); var inner = select.querySelectorAll(':scope .outer .inner'); inner.length; // 0
getElementById()+
getElementById()
This is a no-brainer. Every JavaScript coder should be thoroughly familiar with this method of accessing virtually any element in the DOM. Here is the syntax:
var myVariable = document.getElementById("my_element");
The accessed element can be dynamic, like this:
var myVariable = document.getElementById(myElement);
Notice the literal element has been replaced by a variable (which would be defined elsewhere).
The getElementById
method places whatever object you want to access (for example, a specific link on your page) in a variable called myVariable
, allowing you to access that object directly.
So, if you had a link on your page with its id
set to “my_element”, you could now apply the following code to that element:
myVariable.style.display = "block"; myVariable.style.backgroundColor = "#f00"; myVariable.style.border = "solid 1px #00f";
With the above code, your link will become a block-level element with a red background and a blue border.
When you first start using this method, you’ll probably be scratching your head, wondering what you’re doing wrong, trying to figure out why you’re getting an error. Just keep in mind that JavaScript is case sensitive, so you’ll commonly see this:
var myVariable = document.getElementByID("my_element");
At first glance the above code looks exactly the same as the first code block. Do you see the difference? The case of “Id” has been changed to “ID”, which is a very common mistake for beginners. But after the first few times making that mistake, this method will become old hat.
Another drawback to this method is that you have to apply an id
in your HTML to whatever method you want to access. So, while getElementById
can be very powerful, it can also encourage messy code, as it forces you to clutter your markup.
getElementsByTagName()+
getElementsByTagName()
If you want to keep your markup clean, this method will help you to do so. getElementsByTagName
allows you to traverse the DOM looking for all the elements on your page with a specified tag name. Here is the syntax:
var myLinkCollection = document.getElementsByTagName("a");
With that one line of code, the variable myLinkCollection
becomes an array holding all of the anchor elements on your page. There are so many ways you can take advantage of this method, so I won’t go into too many details here, but here is one powerful use for this method:
var myLinkCollection = document.getElementsByTagName("a"); for (i = 0; i < myLinkCollection.length; i++) { if (myLinkCollection[i].className == "link_class") { myLinkCollection[i].onclick = function() { this.style.backgroundColor = "#f00"; } } }
Don't get overwhelmed if you don't understand everything going on above. The purpose of this code snippet is to show you a practical use for the getElementsByTagName
method.
After you've collected your links into an array, you use a for loop
to navigate through all of them. When you find one that has the class "link_class" attached to it, you apply a click event to that link that will trigger a background color change on that object.
You might wonder: Why not just apply an id
to the link and use getElementById
to access it directly? getElementById
only allows you to access one element, since ids cannot be shared. So, with the above code, you can have many different links with the same class name, and they will all respond to the click event, which, in this case, changes the background color of the link that is clicked.
createElement()+
createElement()
This method does exactly what it says: it creates an element and allows you to place that new element anywhere in the DOM structure.
Using the list example from above, we could add a new list item using the following code:
var myNewListItem = document.createElement("li"); var myNewLink = document.createElement("a");
The above code creates a new <li>
element and a new anchor tag. But these elements don't exist anywhere except as values inside variables. To add our new elements to the DOM, we can use the next method listed in this article.
This creates a new <div> and inserts it before the element with the ID "div1".
<!DOCTYPE html> <html> <head> <title>||Working with elements||</title> </head> <body> <div id="div1">The text above has been created dynamically.</div> </body> </html> <script> document.body.onload = addElement; function addElement () { // create a new div element var newDiv = document.createElement("div"); // and give it some content var newContent = document.createTextNode("Hi there and greetings!"); // add the text node to the newly created div newDiv.appendChild(newContent); // add the newly created element and its content into the DOM var currentDiv = document.getElementById("div1"); document.body.insertBefore(newDiv, currentDiv); } <script> result: Hi there and greetings! The text above has been created dynamically.
createTextNode()+
createTextNode()
HTML elements often consists of both an element node and a text node.
To create a header (e.g. <h1>), you must create both an <h1> element and a text node:
var h = document.createElement("H1") // Create a <h1> element var t = document.createTextNode("Hello World"); // Create a text node h.appendChild(t);
Create a <p> element with some text:
var para = document.createElement("P"); // Create a <p> element var t = document.createTextNode("This is a paragraph."); // Create a text node para.appendChild(t);
before() / after() / prepend() / append()+
node.append(...nodes or strings)
– append nodes or strings at the end ofnode
,node.prepend(...nodes or strings)
– insert nodes or strings into the beginning ofnode
,node.before(...nodes or strings)
–- insert nodes or strings before thenode
,node.after(...nodes or strings)
–- insert nodes or strings after thenode
,
<ol id="ol"> <li>0</li> <li>1</li> <li>2</li> </ol> <script> ol.before('before'); ol.after('after'); let prepend = document.createElement('li'); prepend.innerHTML = 'prepend'; ol.prepend(prepend); let append = document.createElement('li'); append.innerHTML = 'append'; ol.append(append); </script>
The result will be :
before <ol id="ol"> <li>prepend</li> <li>0</li> <li>1</li> <li>2</li> <li>append</li> </ol> after
insertAdjacentHTML()+
The insertAdjacentHTML()
method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position. It does not reparse the element it is being used on, and thus it does not corrupt the existing elements inside that element. This avoids the extra step of serialization, making it much faster than direct innerHTML manipulation.
element.insertAdjacentHTML(position, text);
Positions:
'beforebegin'
: Before theelement
itself.'afterbegin'
: Just inside theelement
, before its first child.'beforeend'
: Just inside theelement
, after its last child.'afterend'
: After theelement
itself.
Visualization of position names
<!-- beforebegin --> <p> <!-- afterbegin --> foo <!-- beforeend --> </p> <!-- afterend -->
When inserting HTML into a page by using insertAdjacentHTML(), be careful not to use user input that hasn't been escaped.
It is not recommended you use insertAdjacentHTML() when inserting plain text; instead, use the Node.textContent property or the Element.insertAdjacentText() method. This doesn't interpret the passed content as HTML, but instead inserts it as raw text.
In practice, only insertAdjacentHTML
is used most of the time. Because for elements and text, we have methods append/prepend/before/after – they are shorter to write and can insert nodes/text pieces.
appendChild()+
appendChild()
- The
Node.appendChild()
method adds a node to the end of the list of children of a specified parent node. - If the given child is a reference to an existing node in the document,
appendChild()
moves it from its current position to the new position (there is no requirement to remove the node from its parent node before appending it to some other node). - This means that a node can't be in two points of the document simultaneously. So if the node already has a parent, the node is first removed, then appended at the new position. The Node.cloneNode() can be used to make a copy of the node before appending it under the new parent. Note that the copies made with cloneNode will not be automatically kept in sync.
- If the given child is a DocumentFragment, the entire contents of the DocumentFragment are moved into the child list of the specified parent node.
element.appendChild(aChild);
- aChild
- The node to append to the given parent node (commonly an element).
Chaining may not work as expected due to appendChild() returning the child element:
var aBlock = doc.createElement('block').appendChild(doc.createElement('b'));
Sets aBlock to <b></b> only, which is probably not what we want.
// Create a new paragraph element, and append it to the end of the document body var p = document.createElement("p"); document.body.appendChild(p);
Let's add the two elements we just created to our list of links using the appendChild
method:
var myNewListItem = document.createElement("li"); var myNewLink = document.createElement("a"); var myLinkList = document.getElementById("list"); myLinkList.appendChild(myNewListItem); myLinkList.lastChild.appendChild(myNewLink);
The above code adds a new anchor tag inside of a new <li>
element at the end of our link list. Keep in mind that this new element will have no attributes and will not be viewable in the source code, since it is a fresh, dynamically created element.
If you're using the Firefox Developer Toolbar, you can use the "view generated source" option to view the new element in context, but the browser's built-in source code reader will not show you any client-side-generated markup.
replace()+
replace()
The replace()
method returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match. If pattern is a string, only the first occurrence will be replaced.
str.replace(regexp|substr, newSubstr|function)
var p = 'The quick brown fox jumps over the lazy dog. If the dog reacted, was it really lazy?'; var regex = /dog/gi; console.log(p.replace(regex, 'ferret')); // expected output: "The quick brown fox jumps over the lazy ferret. If the ferret reacted, was it really lazy?"
remove()+
remove()
The ChildNode.remove()
method removes the object from the tree it belongs to.
<div id="div-01">Here is div-01</div> <div id="div-02">Here is div-02</div> <div id="div-03">Here is div-03</div>
var el = document.getElementById('div-02'); el.remove(); // Removes the div with the 'div-02' id
selectObject.remove(index)
Remove the selected option from the drop-down list:
<form> Select a fruit: <br> <select id="mySelect" size="4"> <option>Apple</option> <option>Pear</option> <option>Banana</option> <option>Orange</option> </select> </form> <br> <button onclick="myFunction()">Remove selected fruit</button> <script> function myFunction() { var x = document.getElementById("mySelect"); x.remove(x.selectedIndex); } </script>
selectedIndex Property+
selectedIndex Property
The selectedIndex property sets or returns the index of the selected option in a drop-down list.
The index starts at 0.
Note: If the drop-down list allows multiple selections it will only return the index of the first option selected.
Note: The value "-1" will deselect all options (if any).
Note: If no option is selected, the selectedIndex property will return -1.
add()+
add()
The HTMLSelectElement.add()
method adds an element to the collection of option elements for this select element.
collection.add(item[, before]);
removeChild()+
removeChild()
The Node.removeChild()
method removes a child node from the DOM and returns the removed node.
var oldChild = node.removeChild(child); OR node.removeChild(child);
child
is the child node to be removed from the DOM.node
is the parent node ofchild
.oldChild
holds a reference to the removed child node, i.e.,oldChild === child
.
The removed child node still exists in memory, but is no longer part of the DOM. With the first syntax form shown, you may reuse the removed node later in your code, via the oldChildobject reference.
In the second syntax form, however, there is no oldChild reference kept, so assuming your code has not kept any other reference to the node elsewhere, it will immediately become unusable and irretrievable, and will usually be automatically deleted from memory after a short time.
If child is actually not a child of the element node, the method throws an exception. This will also happen if child was in fact a child of element at the time of the call, but was removed by an event handler invoked in the course of trying to remove the element (e.g., blur.)
<div id="top"> <div id="nested"></div> </div> //To remove a specified element when knowing its parent node: let d = document.getElementById("top"); let d_nested = document.getElementById("nested"); let throwawayNode = d.removeChild(d_nested); //To remove a specified element without having to specify its parent node: let node = document.getElementById("nested"); if (node.parentNode) { node.parentNode.removeChild(node); } //To remove all children from an element: let element = document.getElementById("top"); while (element.firstChild) { element.removeChild(element.firstChild); }
Error
<div id="top"> </div> <script type="text/javascript"> let top = document.getElementById("top"); let nested = document.getElementById("nested"); // Throws Uncaught TypeError let garbage = top.removeChild(nested); </script>
<div id="top"> <div id="nested"></div> </div> <script type="text/javascript"> let top = document.getElementById("top"); let nested = document.getElementById("nested"); // This first call correctly removes the node let garbage = top.removeChild(nested); // Throws Uncaught NotFoundError garbage = top.removeChild(nested); </script>
In order to remove the element that we just created, we would use the following code:
var myLinkList = document.getElementById("list"); var myRemovedLink = myLinkList.lastChild; myLinkList.removeChild(myRemovedLink);
In this case, we didn't have to remove both the list item and the anchor; removing the list item does both, since it contains the newly created anchor. Of course, if we had not created any new elements, then the above code would serve to remove the last list item, regardless of whether it was a newly created one, or one that exists naturally in our markup.
replaceChild()+
The Node.replaceChild()
method replaces a child node within the given (parent) node.
replacedNode = parentNode.replaceChild(newChild, oldChild);
newChild
is the new node to replaceoldChild
. If it already exists in the DOM, it is first removed.oldChild
is the existing child to be replaced.replacedNode
is the replaced node. This is the same node asoldChild
.
<div> <strong>hello</strong> </div <script> var em = document.createElement('em'); var strong = document.querySelector('strong'); var div = document.querySelector('div'); em.textContent = 'hi'; div.replaceChild(em, strong); </script>
// Given: // <div> // <span id="childSpan">foo bar</span> // </div> // Create an empty element node // without an ID, any attributes, or any content var sp1 = document.createElement("span"); // Give it an id attribute called 'newSpan' sp1.id = "newSpan"; // Create some content for the new element. var sp1_content = document.createTextNode("new replacement span element."); // Apply that content to the new element sp1.appendChild(sp1_content); // Build a reference to the existing node to be replaced var sp2 = document.getElementById("childSpan"); var parentDiv = sp2.parentNode; // Replace existing node sp2 with the new span element sp1 parentDiv.replaceChild(sp1, sp2); // Result: // <div> // <span id="newSpan">new replacement span element.</span> // </div>
cloneNode()+
The Node.cloneNode()
method returns a duplicate of the node on which this method was called.
var dupNode = node.cloneNode([deep]);
node
- The node to be cloned.
dupNode
- The new node that will be a clone of
node
deep
Optionaltrue
if the children of the node should also be cloned, orfalse
to clone only the specified node.
var p = document.getElementById("para1"); var p_prime = p.cloneNode(true);
Cloning a node copies all of its attributes and their values, including intrinsic (in–line) listeners. It does not copy event listeners added using addEventListener() or those assigned to element properties (e.g., node.onclick = fn). Moreover, for a <canvas> element, the painted image is not copied.
The duplicate node returned by cloneNode() is not part of the document until it is added to another node that is part of the document using Node.appendChild()
or a similar method. It also has no parent until it is appended to another node.
If deep is set to false, child nodes are not cloned. Any text that the node contains is not cloned either, as it is contained in one or more child Text nodes.
If deep evaluates to true, the whole subtree (including text that may be in child Text nodes) is copied too. For empty nodes (e.g., <img> and <input> elements) it doesn't matter whether deep is set to true or false.
If the original node has an ID and the clone is to be placed in the same document, the ID of the clone should be modified to be unique. Name attributes may need to be modified also, depending on whether duplicate names are expected.
To clone a node for appending to a different document, use Document.importNode() instead.
insertBefore()+
insertBefore()
The insertBefore() method inserts a node as a child, right before an existing child, which you specify.
Tip: If you want to create a new list item, with text, remember to create the text as a Text node which you append to the <li> element, then insert <li> to the list.
You can also use the insertBefore method to insert/move an existing element
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
insertedNode
The node being inserted, that isnewNode
parentNode
The parent of the newly inserted node.newNode
The node to be inserted.referenceNode
The node before whichnewNode
is inserted.
If referenceNode is null, the newNode is inserted at the end of the list of child nodes.
<div id="parentElement"> <span id="childElement">foo bar</span> </div> <script> // Create the new node to insert var newNode = document.createElement("span"); // Get a reference to the parent node var parentDiv = document.getElementById("childElement").parentNode; // Begin test case [ 1 ] : Exist a childElement --> All working correctly var sp2 = document.getElementById("childElement"); parentDiv.insertBefore(newNode, sp2); // End test case [ 1 ] // Begin test case [ 2 ] : childElement is of Type undefined var sp2 = undefined; // Not exist a node of id "childElement" parentDiv.insertBefore(newNode, sp2); // Implicit dynamic cast to type Node // End test case [ 2 ] // Begin test case [ 3 ] : childElement is of Type "undefined" ( string ) var sp2 = "undefined"; // Not exist a node of id "childElement" parentDiv.insertBefore(newNode, sp2); // Generate "Type Error: Invalid Argument" // End test case [ 3 ] </script>
<div id="parentElement"> <span id="childElement">foo bar</span> </div> <script> // Create a new, plain <span> element var sp1 = document.createElement("span"); // Get a reference to the element, before we want to insert the element var sp2 = document.getElementById("childElement"); // Get a reference to the parent element var parentDiv = sp2.parentNode; // Insert the new element into the DOM before sp2 parentDiv.insertBefore(sp1, sp2); </script>
var newItem = document.createElement("LI"); // Create a <li> node var textnode = document.createTextNode("Water"); // Create a text node newItem.appendChild(textnode); // Append the text to <li> var list = document.getElementById("myList"); // Get the <ul> element to insert a new node list.insertBefore(newItem, list.childNodes[0]); // Insert <li> before the first child of <ul>
Move a <li> element from one list to another:
var node = document.getElementById("myList2").lastChild; var list = document.getElementById("myList1"); list.insertBefore(node, list.childNodes[0]);
There is no insertAfter()
method. It can be emulated by combining the insertBefore method with Node.nextSibling()
.
In the previous example, sp1 could be inserted after sp2 using:
parentDiv.insertBefore(sp1, sp2.nextSibling);
If sp2 does not have a next sibling, then it must be the last child — sp2.nextSibling returns null, and sp1 is inserted at the end of the child node list (immediately after sp2).
Insert an element before the first child element, using the firstChild
property.
// Get a reference to the element in which we want to insert a new node var parentElement = document.getElementById('parentElement'); // Get a reference to the first child var theFirstChild = parentElement.firstChild; // Create a new element var newElement = document.createElement("div"); // Insert the new element before the first child parentElement.insertBefore(newElement, theFirstChild);
When the element does not have a first child, then firstChild
is null. The element is still appended to the parent, after the last child. Since the parent element did not have a first child, it did not have a last child either. Consequently, the new element is the only element, after insertion.
getAttribute()+
getAttribute()
The getAttribute
method allows you to access the value of any attribute on any element on your page. For example, going back to our list of links, suppose we had the following code:
var attribute = element.getAttribute(attributeName);
attribute
is a string containing the value ofattributeName
.attributeName
is the name of the attribute whose value you want to get.
let div1 = document.getElementById('div1'); let align = div1.getAttribute('align'); alert(align); // Shows the value of align for the element with id="div1"
<ul id="list"> <li><a href="link1.html" class="link_one">Link Number One</a></li> <li><a href="link2.html">Link Number Two</a></li> <li><a href="link3.html">Link Number Three</a></li> <li><a href="link4.html">Link Number Four</a></li> <li><a href="link5.html" id="link_5" rel="external">Link Number Five</a></li> </ul>
We've added a new link with an id
of "link_5" and a rel
attribute with the value "external".
If we want to read the rel
attribute of the fifth link in our list, we would use the following code:
var myLinkFive = document.getElementById("link_5"); var myLinkAttribute = myLinkFive.getAttribute("rel");
Now the value of the variable myLinkAttribute
will contain the rel
attribute's value, which, in this case, is "external". This method could be used to target links with specific rel
values so you can open those links in a new window.
- When called on an HTML element in a DOM flagged as an HTML document, getAttribute() lower-cases its argument before proceeding.
- You should use element.hasAttribute() to check for an attribute's existence prior to calling getAttribute()
- if it is possible that the requested attribute does not exist on the specified element.
- If the given attribute does not exist, the value returned will either be null or "" (the empty string);
setAttribute()+
setAttribute()
Writing a new value for a given attribute is another useful method, and can be used in conjunction with getAttribute
. Let's say we wanted to change the value of the rel
attribute from the previous example. Here's how that is accomplished:
To get the current value of an attribute, use getAttribute(); to remove an attribute, call removeAttribute().
var myLinkFive = document.getElementById("link_5"); myLinkFive.setAttribute("rel", "nofollow");
With the above code, the fifth link in our list would now have a rel
attribute with the value "nofollow", instead of "external".
Keep in mind that an attribute can not only be changed, but it can be added. So, if our fifth link did not have a rel
attribute, the above code would still work, and would create the rel
attribute and assign it a value on the fly.
TML DOM setAttributeNode() Method
var h1 = document.getElementsByTagName("H1")[0]; // Get the first <h1> element in the document var att = document.createAttribute("class"); // Create a "class" attribute att.value = "democlass"; // Set the value of the class attribute h1.setAttributeNode(att); // Add the class attribute to <h1>
Set the href attribute node of a <a> element:
var anchor = document.getElementById("myAnchor"); // Get the <a> element with id="myAnchor" var att = document.createAttribute("href"); // Create a "href" attribute att.value = "https://www.w3schools.com"; // Set the value of the href attribute anchor.setAttributeNode(att); // Add the href attribute to <a>
<button>Hello World</button> <script> var b = document.querySelector("button"); b.setAttribute("name", "helloButton"); b.setAttribute("disabled", ""); </script>
removeAttribute()+
removeAtrribute()
The removeAttribute()
method removes the specified attribute from an element.
The difference between this method and the removeAttributeNode() method is that the removeAttributeNode()
method removes the specified Attr object, while this method removes the attribute with the specified name. The result will be the same. Also this method has no return value, while the removeAttributeNode()
method returns the removed attribute, as an Attr object.
document.getElementsByTagName("H1")[0].removeAttribute("class");
Remove the href attribute from an <a> element:
document.getElementById("myAnchor").removeAttribute("href");
// Given: <div id="div1" align="left" width="200px"> document.getElementById("div1").removeAttribute("align"); // Now: <div id="div1" width="200px">
document.forms +
document.forms
Almost every website that you work on will have a form of some sort on it. While you can access a form or form element directly using getElementById
or another method mentioned above, the best way to access any given form is using the document.forms
syntax, which is basically acessing the "forms" collection of the document object.
For example, look at the following XHTML:
<form id="my_form" method="post" action="form.html"> <input type="checkbox" value="one" name="options" id="option1" checked="checked" /> One<br /> <input type="checkbox" value="two" name="options" id="option2" /> Two<br /> <input type="checkbox" value="three" name="options" id="option3" /> Three<br /> </form>
We could find out the "checked" state of any of the checkboxes with the following code:
var myCheckBoxOne = document.forms["my_form"]["option1"]; alert(myCheckBoxOne.checked);
In the above example, the alert message will display "true", because the checkbox that we're accessing ("option1") has its checked
attribute set. If we change the code to access "option2", the result will be an alert message of "false".
Radio buttons are accessed similarly, but instead of being treated as separate entities (as is usually the case with checkboxes), radio buttons are accessed as one collective object. To find out which radio button in a group is selected, we can use a loop. Take a look at the following XHTML:
<form id="my_form" method="post" action="form.html"> <input type="radio" value="one" name="options" /> One<br /> <input type="radio" value="two" name="options" checked="checked" /> Two<br /> <input type="radio" value="three" name="options" /> Three<br /> </form>
And here is the loop that will alert a message that displays the "value" attribute of the selected radio button:
var radioButtonGroup = document.forms["my_form"]["options"]; for (var i = 0; i < radioButtonGroup.length; i++) { if (radioButtonGroup[i].checked == true) { alert("Your selection is " + radioButtonGroup[i].value); } }
Getting form information
<!DOCTYPE html> <html lang="en"> <head> <title>document.forms example</title> </head> <body> <form id="robby"> <input type="button" onclick="alert(document.forms[0].id);" value="robby's form" /> </form> <form id="dave"> <input type="button" onclick="alert(document.forms[1].id);" value="dave's form" /> </form> <form id="paul"> <input type="button" onclick="alert(document.forms[2].id);" value="paul's form" /> </form> </body> </html>
Getting an element from within a form
var selectForm = document.forms[index]; var selectFormElement = document.forms[index].elements[index];
Named form access
<!DOCTYPE html> <html lang="en"> <head> <title>document.forms example</title> </head> <body> <form name="login"> <input name="email" type="email"> <input name="password" type="password"> <button type="submit">Log in</button> </form> <script> var loginForm = document.forms.login; // Or document.forms['login'] loginForm.elements.email.placeholder = 'test@example.com'; loginForm.elements.password.placeholder = 'password'; </script> </body> </html>
classList +
Literally Everything You Need To Know About classList
blog.webdevsimplified.com/2020-11/class-list
element.classList.add('new-class', 'another-class') console.log(element.classList.value) // new-class another-class element.classList.remove('another-class') console.log(element.classList.value) // new-class
console.log(element.classList.contains('new-class')) // false element.classList.add('new-class') console.log(element.classList.contains('new-class')) // true
element.classList.toggle('new-class')
if (element.classList.contains('new-class')) { element.classList.remove('new-class') } else { element.classList.add('new-class') }
element.classList.add('one', 'two') element.classList.forEach(className => { console.log(className) }) // one // two
innerHTML +
innerHTML
The innerHTML
property is an interesting beast. Firstly, it is a nonstandard element, but is very well supported accross all browsers and platforms. IE evidently has a few problems when accessing this property inside of a form, but generally it has good support.
Basically, innerHTML
is a way of accessing, for the purpose of writing to, the content inside of an XHTML element. It comes in handy with Ajax requests because you can choose an element on your page, then write the Ajax-loaded content straight into that element via innerHTML
. Here's a simple example:
var myContentHolder = document.getElementById("content"); myContentHolder.innerHTML = "This is the dynamic content created by the innerHTML property
";
With the code above, the element on the page with the id
of "content" will now have content between its tags consisting of the text "This is the dynamic content created by the innerHTML property" wrapped in paragraph tags.
The innerHTML
element can also be read directly and appended to. (Thanks to Stacey in the comments for pointing out my error in regards to the drawbacks of this property, which I've corrected here.)
Well, I hope you enjoyed this list. I tried to cover some practical methods that I've personally used on many projects, and even a few that I haven't used too often but that I feel could offer solutions to various issues on the client side.
Although I didn't delve too deeply into the intricacies of these methods, I encourage all beginner and intermediate JavaScript coders to research each of these methods more fully, so as to have a stronger grasp of how the DOM is manipulated. Even if you rely heavily on JavaScript libraries, knowledge of essential DOM manipulation is a huge plus, as it helps you fully understand the different methods of accessing, adding to, and removing, page elements.
createDocumentFragment()+
getComputedStyle()+
addEventListener() +
Learn JavaScript Event Listeners In 18 Minutes
addEventListener() - MDN
Events refer to what happens to an HTML element, such as clicking, focusing, or loading, to which we can react with JavaScript. We can assign JS functions to listen for these events in elements and do something when the event had occured.
There are three ways you can assign a function to a certain event.
If foo()
is a custom function, you can register it as a click event listener (call it when the button element is clicked) in three ways:
// HTML <button onclick=foo>Alert</button>
var btn = document.querySelector('button'); btn.onclick=foo;
var btn = document.querySelector('button'); btn.addEventListener('click', foo);
The method addEventListener()
(the third solution) has some pros; it is the latest standard – allowing the assignment of more than one function as event listeners to one event – and comes with a useful set of options.
ele.addEventListener(evt, listener, [options]);
- ele – The HTML element the event listener will be listening for.
- evt – The targeted event.
- listener – Typically, a JavaScript function.
- options – (optional) An object with a set of boolean properties (listed below).
Options | What happens, when it is set to true ? |
capture |
Stops event bubbling, i.e. prevents calling of any event listeners for the same event type in the element’s ancestors. To use this feature, you can use 2 syntaxes:
|
once |
Listener is called only the first time the event happens, then it is automatically detached from the event, and won’t be triggered by it anymore. |
passive |
The default action of the event cannot be stopped with the preventDefault() method. |
// Function to change the content of t2 function modifyText() { var t2 = document.getElementById("t2"); if (t2.firstChild.nodeValue == "three") { t2.firstChild.nodeValue = "two"; } else { t2.firstChild.nodeValue = "three"; } } // add event listener to table var el = document.getElementById("outside"); el.addEventListener("click", modifyText, false);
In this code, modifyText()
is a listener for click events registered using addEventListener()
. A click anywhere in the table bubbles up to the handler and runs modifyText()
.
Selectors
removeEventListener() +
removeEventListener()
The removeEventListener()
method detaches an event listener previously added with the addEventListener()
method from the event it is listening for.
Given an event listener previously added by calling addEventListener(), you may eventually come to a point at which you need to remove it. Obviously, you need to specify the same typeand listener parameters to removeEventListener()
, but what about the options or useCapture parameters?
While addEventListener()
will let you add the same listener more than once for the same type if the options are different, the only option removeEventListener()
checks is the capture/useCapture flag. Its value must match for removeEventListener()
to match, but the other values don't.
For example, consider this call to addEventListener()
:
element.addEventListener("mousedown", handleMouseDown, true);
Now consider each of these two calls to removeEventListener()
:
element.removeEventListener("mousedown", handleMouseDown, false); // Fails element.removeEventListener("mousedown", handleMouseDown, true); // Succeeds
The first call fails because the value of useCapture doesn't match. The second succeeds, since useCapture matches up.
element.addEventListener("mousedown", handleMouseDown, { passive: true });
Here, we specify an options object in which passive is set to true, while the other options are left to the default value of false.