CSSE 290 Web Programming

Lecture 16: Unobtrusive JavaScript; DOM tree

Reading: 9.1-9.4

Attribution: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.

Otherwise noted: Claude Anderson was given permission to modify the slides for CSSE 290 at Rose-Hulman by author Jessica Miller. The authors' original slides, based on Web Programming Step by Step, can be seen at http://webstepbook.com.
Some of the examples in some days' slides are from David Fisher at Rose-Hulman, who was kind enough to allow me to use them. My intention is to mark these examples with [DSF].

Valid HTML Valid CSS!

flexible 15-puzzle continued

15-puzzle picture

9.1.1: Unobtrusive JavaScript

Unobtrusive JavaScript

Obtrusive event handlers (bad)

<button onclick="okayClick();">OK</button>
// called when OK button is clicked
function okayClick() {
	alert("booyah");
}

Attaching an event handler in JavaScript code

// where element is a DOM element object
element.onevent = function;
<button id="ok">OK</button>
var okButton = document.getElementById("ok");
okButton.onclick = okayClick;

When does my code run?

<html>
	<head>
		<script src="myfile.js" type="text/javascript"></script>
	</head>
	<body> ... </body> </html>
// global code
var x = 3;
function f(n) { return n + 1; }
function g(n) { return n - 1; }
x = f(x);

A failed attempt at being unobtrusive

<html>
	<head>
		<script src="myfile.js" type="text/javascript"></script>
	</head>
	<body>
		<div><button id="ok">OK</button></div>
// global code
document.getElementById("ok").onclick = okayClick;   // error: null

The window.onload event

// this will run once the page has finished loading
function functionName() {
	element.event = functionName;
	element.event = functionName;
	...
}

window.onload = functionName;   // global code

An unobtrusive event handler

<button id="ok">OK</button>   <!-- look Ma, no JavaScript! -->
// called when page loads; sets up event handlers
function pageLoad() {
	document.getElementById("ok").onclick = okayClick;
}

function okayClick() {
	alert("booyah");
}

window.onload = pageLoad;  // global code

Common unobtrusive JS errors

Prototype's $ Function

Recap: Anonymous functions

function(parameters) {
	statements;
}

Anonymous function example

window.onload = function() {
	var okButton = document.getElementById("ok");
	okButton.onclick = okayClick;
};

function okayClick() {
	alert("booyah");
}
window.onload = function() {
	var okButton = document.getElementById("ok");
	okButton.onclick = function() {
		alert("booyah");
	};
};

Unobtrusive styling

function okayClick() {
	this.style.color = "red";
	this.className = "highlighted";
}
.highlighted { color: red; }

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 * returns the first element that would be matched by the given CSS selector string
querySelectorAll * 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":

// var addrParas = $("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>

Creating new nodes

name description
document.createElement("tag") creates and returns a new empty DOM node representing an element of that type
// 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!";
$("main").appendChild(p);

Removing a node from the page

function slideClick() {
	var bullets = document.getElementsByTagName("li");
	for (var i = 0; i < bullets.length; i++) {
		if (bullets[i].innerHTML.indexOf("children") >= 0) {
			bullets[i].parentNode.removeChild(bullets[i]);
		}
	}
}

DOM versus innerHTML hacking

Why not just code the previous example this way?

function slideClick() {
	$("thisslide").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() {
	$("main").innerHTML += "<p style='color: red; " +
			"margin-left: 50px;' " +
			"onclick='myOnClick();'>" +
			"A paragraph!</p>";
}

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>