DOM modifications is the key to making pages dynamic. Using the methods described below, it is possible to construct new page elements and fill them on-the-fly.
The DOM manipulation methods described above are defined in DOM Level 1.
Creating elements
There are following methods for creating new elements in DOM:
document.createElement(tag)
- Creates a new DOM element of type node:
var div = document.createElement('div')
document.createTextNode(text)
- Creates a new DOM element of type text:
var textElem = document.createTextNode('Robin was here')
The createElement
is the most commonly used method, but createTextNode
is also good. It creates a text node that can be appended to another element.
For an empty element, creating a text node and appending it works much faster than innerHTML
in most modern browsers.
But innerHTML
is simpler and supports nested tags, so they both find their place in the world.
An element can also be cloned:
elem.cloneNode(true)
- Clones an element deeply, with all descendants.
elem.cloneNode(false)
- Clones an element only, with attributes, but without children.
Adding elements
To do something with the element, you need to call the corresponding method of its parent:
parentElem.appendChild(elem)
- Appends
elem
to the children ofparentElem
.The following example demonstrates creating and adding new element to
BODY
:
<div> ... </div> <script> var div = document.body.children[0] var span = document.createElement('span') span.innerHTML = 'A new span!' div.appendChild(span) </script>
The new node becomes a last child of the
parentElem
.There’s an empty DOM node
elem
. What’s the difference?
elem.appendChild(document.createTextNode(text))
versus
elem.innerHTML = text
SolutioncreateTextNode
escapes node content.Compare the two examples.
createTextNode
makes text'<b>tag</b>'
:
<div></div> <script> var text = '**tag**' var elem = document.body.children[0] elem.appendChild(document.createTextNode(text)) </script>
innerHTML
assigns HTML<b>tag</b>
:
<div></div> <script> var text = '**tag**' var elem = document.body.children[0] elem.innerHTML = text </script>
parentElem.insertBefore(elem, nextSibling)
- Inserts
elem
into the children ofparentElem
before the elementnextSibling
.The following example inserts a new node before the first child:
<div> ... </div> <script> var div = document.body.children[0] var span = document.createElement('span') span.innerHTML = 'A new span!' div.insertBefore(span, div.firstChild) </script>
Note that you
insertBefore
with second argumentnull
works asappendChild
.elem.insertBefore(newElem, null) // same as elem.appendChild(newElem)
All insertion methods return the inserted node.
Removing nodes
There are two main methods for removing nodes from DOM:
parentElem.removeChild(elem)
- Remove the
elem
from the children ofparentElem
. parentElem.replaceChild(elem, currentElem)
- Replace the child element of
parentElem
, referenced bycurrentElem
with theelem
.
Both of them return a removed node which can later be reinserted into the DOM.
If you want to move an element, you don’t have to remove it first.
elem.appendChild/insertBefore
remove elem
from it’s previous place automatically.
The following example moves the last child to the top of children list:
<div>First div</div> <div>Last div</div> <script> var first = document.body.children[0] var last = document.body.children[1] document.body.insertBefore(last, first) </script>
The removal occurs automatically when insertion methods are called for a node which already has a parent.
Tasks and examples
The following tasks can serve as examples depending on whether you read or try to solve them. Of course, it’s always better to solve
Write a function which removes an element from DOM without referencing its parent.
The syntax should be: remove(elem)
<div>Very</div> <div>Secret</div> <div>Child</div> <script> var elem = document.body.children[0] function remove(elem) { /* your code */ *!* remove(elem) // <-- should remove the element */!* </script>
The parent of elem
is referenced by the parentNode
property.
And better don’t forget to return the removed element for compatibility.
So the code can be like this:
function remove(elem) { return elem.parentNode.removeChild(elem) }
Write a function insertAfter(elem, refElem)
to insert elem
right after refElem
.
<div>Very</div> <div>Secret</div> <script> var elem = document.createElement('div') elem.innerHTML = '**Child**' function insertAfter(elem, refElem) { /* your code */ insertAfter(elem, document.body.firstChild) // <--- should work insertAfter(elem, document.body.lastChild) // <--- should work </script>
To insert an element after refElem
, we can insert it before refElem.nextSibling
.
But what if there is no nextSibling
? That means refElem
is the last child of its parent, so we can just call appendChild
.
The code:
function insertAfter(elem, refElem) { var parent = refElem.parentNode var next = refElem.nextSibling if (next) { return parent.insertBefore(elem, next) } else { return parent.appendChild(elem) } }
But the code could be much shorter if it used insertBefore
null second argument feature:
function insertAfter(elem, refElem) { return elem.parentNode.insertBefore(elem, refElem.nextSibling) }
If there is no nextSibling
then the second argument of insertBefore
becomes null
and then insertBefore(elem,null)
works as appendChild
.
Write a function removeChildren
to remove all children of an element.
<div>Very</div> <div>Secret</div> <div>Children</div> <script> function removeChildren(elem) { /* your code */ removeChildren(document.body) // makes BODY absolutely empty </script>
First, let’s check a way how it shouldn’t be done:
function removeChildren(elem) { for(var k=0; k<elem.childNodes.length;k++) { elem.removeChild(elem.childNodes[k]) } }
If you check it in action - you’ll find that it doesn’t work.
That’s because childNodes
always starts from 0, it autoshifts when first child is removed. But k
increases +1 every iteration. So, k
skips half of nodes.
The right solution:
function removeChildren(elem) { while(elem.lastChild) { elem.removeChild(elem.lastChild) } }
Another solution:
function removeChildren(elem) { elem.innerHTML = '' }
Create an interface to generate the list.
For each item:
- Prompt the user for it’s contents.
- Create the item and append it to
UL
. - The process ends when user presses ESC.
All elements must be created dynamically.
The working example is here: tutorial/browser/dom/createList.html
P.S. prompt
returns null
if user pressed ESC.
The solution is self-descriptive:
<!DOCTYPE HTML> <html> <body> <h1>Creation of the list</h1> <script> var ul = document.createElement('ul') document.body.appendChild(ul) while (true) { var data = prompt("Enter the contents for the item", "") if (data === null) { break } var li = document.createElement('li') li.appendChild(document.createTextNode(data)) ul.appendChild(li) } </script> </body> </html>Open the code in new window
Note checking for null
value as a loop-breaking condition. The prompt
only returns it when ESC is pressed.
LI
contents is populated by document.createTextNode
to ensure proper work of <, > etc.
Summary
Creation methods:
document.createElement(tag)
- creates a new element node.document.createTextNode(value)
- creates a new text node with given valueelem.cloneNode(deep)
- clones the element
Inserting and removing methods are called from parent node. All of them return elem
:
parent.appendChild(elem)
parent.insertBefore(elem, nextSibling)
parent.removeChild(elem)
parent.replaceChild(elem, currentElem)