Modifying and Creating Elements

CSCI-UA.0480-008

Modifying the DOM

What were some methods that we could use to add or get rid of elements from the DOM

Swapping Paragraphs

We didn't have a chance to try this previously… so let's check out another sample page. Starting with:


const content = document.getElementById('content');
const paragraphs = document.getElementsByTagName('p');

Move the 3rd paragraph between the first two.


const inserted = content.insertBefore(paragraphs[2], paragraphs[1]);

Now, instead of just inserting before, let's replace paragraph "Two" with paragraph "Three":


const replaced = content.replaceChild(paragraphs[2], paragraphs[1]);

Removing Elements

We also looked at removing elements with removeChild. This was our first attempt:


const div = document.getElementById('content');
const p = div.getElementsByTagName('p');

for(let i = 0; i < p.length; i++) {
	div.removeChild(p[i]);
}

But… what happened?

There was an element left over because we were editing a live data structure. How did we fix this?

Removing Elements Continued

To get around this issue, we could:

  • work backwards
  • use a while loop

while (div.firstChild) {
  div.removeChild(div.firstChild);
}
  • use a copy…

const copy = Array.prototype.slice.call(p, 0)
copy.forEach(function(ele) {
	div.removeChild(ele)
});

Reading and Modifying a Node's Content

The following Node property and methods allow you to read and / or modify that Node's content:

nodeValue - represents content of text and comment nodes, null otherwise


// assuming we have an element_node, and we know its first child is a text element
console.log(node.firstChild.nodeValue);
node.firstChild.nodeValue = 'new text';

textContent - the text content of the node and all of its descendants (!)


const text = element.textContent; 
element.textContent = "this is some sample text";

There are other properties similar to textContent, such as innerHTML (which includes markup) and innerText which is aware of styling (for example, ignores hidden elements).

Node Content Continued

What do the following lines of code represent / do based on the markup below?


<div id="content">
	<p>One</p>
	<p class="cta">Two</p>
	<p class="cta">Three</p>
</div>

document.body.textContent
document.body.innerHTML
document.body.nodeValue
const p = document.getElementsByTagName('p')[0]
p.firstChild.nodeValue
p.firstChild.nodeValue = 'Surprised?'
p.textContent = 'Maybe not.'

Creating Nodes

The following methods actually create new Nodes!

Note… that they're called on the built-in document object, not on Node or an instance of node.

Replacing All Paragraphs With Text

Replace each paragraph element with text that says "this was a paragraph".


<div id="content">
	<p>One</p>
	<p class="cta">Two</p>
	<p class="cta">Three</p>
</div>

const div = document.getElementById('content');
const p = div.getElementsByTagName('p');

for(let i = p.length - 1; i >= 0; i--) {
	div.replaceChild( 
		document.createTextNode("this was a paragraph"),
		p[i]);
}

Now Let's Try Adding Some Elements

Instead of just a text node, replace each paragraph with an h1 (a header). The text should remain the same.

  • in a loop…
  • create an h1 element node and a text node
  • add the text node to the h1
  • replace the div

const div = document.getElementById('content');
const p = div.getElementsByTagName('p');

for(let i = p.length - 1; i >= 0; i--) {
	const header = document.createElement("h1");
	const content = document.createTextNode(p[i].textContent);
	header.appendChild(content);
	div.replaceChild(header, p[i]);
}

Convenience

Creating each element and adding a child was a bit of a drag…

The book uses a convenience method to add an element and an arbitrary number of child elements.

It acts like this: elt(type, [, child1, ..., child2);

  • creates an element of type type
  • an optional list of Elements follows
  • each element will be added as a child
  • if the element is just a string, create and add a text node

How would we create this?

elt Implementation

A potential implementation…

  • uses the arguments object
  • checks typeof to determine whether or not to create a text node

function elt(type) {
	const ele = document.createElement(type);
	// start at 1 or else we'll get the type argument!
	for (let i = 1; i < arguments.length; i++) {
		let child = arguments[i];
		if (typeof child === "string") {
			child = document.createTextNode(child);
		}
		ele.appendChild(child);
	}
	return ele;
}
const ul = elt('ul', elt('li', 'item one'), elt('li', 'item two'));
document.body.appendChild(ul);