Web Programming Step by Step, 2nd Edition

Lecture 16: The DOM Tree

Reading: 8.2.6, 9.3–9.4

Except where otherwise noted, the contents of this document are Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst. All rights reserved. Any redistribution, reproduction, transmission, or storage of part or all of the contents in any form is prohibited without the author's expressed written permission.

Valid HTML5 Valid CSS

9.3: The DOM Tree

Complex DOM manipulation problems

How would we do each of the following in JavaScript code? Each involves modifying each one of a group of elements ...

The DOM tree

DOM tree

Selecting groups of DOM objects

name description
getElementsByTagName returns array of descendents with the given tag, such as "div"
getElementsByName returns array of descendents with the given name attribute (mostly useful for accessing form controls)
querySelector html5 returns the first element that would be matched by the given CSS selector string
querySelectorAll html5 returns an array of all elements that would be matched by the given CSS selector string

Getting all elements of a certain type

highlight all paragraphs in the document:

var allParas = document.querySelectorAll("p");
for (var i = 0; i < allParas.length; i++) {
	allParas[i].style.backgroundColor = "yellow";
}
<body>
	<p>This is the first paragraph</p>
	<p>This is the second paragraph</p>
	<p>You get the idea...</p>
</body>

Complex selectors

highlight all paragraphs inside of the section with ID "address":

// document.getElementById("address").getElementsByTagName("p")
var addrParas = document.querySelectorAll("#address p");
for (var i = 0; i < addrParas.length; i++) {
	addrParas[i].style.backgroundColor = "yellow";
}
<p>This won't be returned!</p>
<div id="address">
	<p>1234 Street</p>
	<p>Atlanta, GA</p>
</div>

Common querySelectorAll issues

Creating new nodes

name description
document.createElement("tag") creates and returns a new empty DOM node representing an element of that type
document.createTextNode("text") creates and returns a text node containing given text
// create a new <h2> node
var newHeading = document.createElement("h2");
newHeading.innerHTML = "This is a heading";
newHeading.style.color = "green";

Modifying the DOM tree

Every DOM element object has these methods:

name description
appendChild(node) places given node at end of this node's child list
insertBefore(newold) places the given new node in this node's child list just before old child
removeChild(node) removes given node from this node's child list
replaceChild(newold) replaces given child with new node
var p = document.createElement("p");
p.innerHTML = "A paragraph!";
document.getElementById("main").appendChild(p);

DOM versus innerHTML hacking

Why not just code the previous example this way?

function slideClick() {
	document.getElementById("main").innerHTML += "<p>A paragraph!</p>";
}
  • Imagine that the new node is more complex:
    • ugly: bad style on many levels (e.g. JS code embedded within HTML)
    • error-prone: must carefully distinguish " and '
    • can only add at beginning or end, not in middle of child list
function slideClick() {
	document.getElementById("main").innerHTML += "<p style='color: red; " +
			"margin-left: 50px;' " +
			"onclick='myOnClick();'>" +
			"A paragraph!</p>";
}

Removing a node from the page

function slideClick() {
	var bullet = document.getElementById("removeme");
	bullet.parentNode.removeChild(bullet);
}

Problems with reading/changing styles

<button id="clickme">Click Me</button>
window.onload = function() {
	document.getElementById("clickme").onclick = biggerFont;
};
function biggerFont() {
	var button = document.getElementById("clickme");
	var size = parseInt(button.style.fontSize);
	button.style.fontSize = (size + 4) + "pt";
}

Accessing elements' existing styles

window.getComputedStyle(element).propertyName
function biggerFont() {
	// turn text yellow and make it bigger
	var clickMe = document.getElementById("clickme");
	var size = parseInt(window.getComputedStyle(clickMe).fontSize);
	clickMe.style.fontSize = (size + 4) + "pt";
}

Common bug: incorrect usage of existing styles

Getting/setting CSS classes

function highlightField() {
	// turn text yellow and make it bigger
	var text = document.getElementById("text");
	if (!text.className) {
		text.className = "highlight";
	} else if (text.className.indexOf("invalid") < 0) {
		text.className += " highlight";   // awkward
	}
}

Getting/setting CSS classes with classList html5

function highlightField() {
	// turn text yellow and make it bigger
	var text = document.getElementById("text");
	if (!text.classList.contains("invalid")) {
		text.classList.add("highlight");
	}
}

Types of DOM nodes

<p>
	This is a paragraph of text with a 
	<a href="/path/page.html">link in it</a>.
</p>
DOM Tree

Traversing the DOM tree manually

every node's DOM object has the following properties:

name(s) description
firstChild, lastChild start/end of this node's list of children
childNodes array of all this node's children
nextSibling, previousSibling neighboring nodes with the same parent
parentNode the element that contains this node

DOM tree traversal example

<p id="foo">This is a paragraph of text with a 
	<a href="/path/to/another/page.html">link</a>.</p>
navigate tree

Element vs. text nodes

<div>
	<p>
		This is a paragraph of text with a 
		<a href="page.html">link</a>.
	</p>
</div>

8.2.6: Debugging Common Errors

Debugging JS code in Firebug

Firebug JS

JSLint

JSLint

JavaScript "strict" mode

screenshot
"use strict";

your code...