CPS 353: Internet Programming

JavaScript and the DOM

Guest lecture: Matt Jardine

Gordon College

Last Modified: 11/04/2015

Selected content adapted from material by Marty Stepp, Jessica Miller, and Victoria Kirst © 2012. Used by permission.

Agenda

Introductions

11.1: Key JavaScript Concepts

Client-side scripting

client-side scripting

Why use client-side programming?

Server-side languages already allows us to create dynamic web pages. Why also use client-side scripting?

What is JavaScript?

JavaScript vs. Java and C#

Java + mary jane, da endo, aight = JavaScript

JavaScript vs. PHP

JS <3 php

Loading a JavaScript file: script

<script src="filename" type="text/javascript"></script>
<script src="example.js" type="text/javascript"></script>

A JavaScript statement: alert

alert("message");
alert("IE6 detected.  Suck-mode enabled.");
alert

Variables and types

var name = expression;
var age = 32;
var weight = 127.4;
var clientName = "Connie Client";

Event-driven programming

event

Buttons: <button>

the canonical clickable UI control (inline)

<button>Click me!</button>

JavaScript functions

function name() {
	statement ;
	statement ;
	...
	statement ;
}
function myFunction() {
	alert("Hello!");
	alert("How are you?");
}

Event handlers

<element attributes onclick="function();">...
<button onclick="myFunction();">Click me!</button>

Document Object Model (DOM)

a set of JavaScript objects that represent each element on the page

DOM

DOM element objects

dom object

Accessing elements: document.getElementById

var name = document.getElementById("id");
<button onclick="changeText();">Click me!</button>
<input id="output" type="text" value="replace me" />
function changeText() {
	var textbox = document.getElementById("output");
	textbox.value = "Hello, world!";
}

More advanced example

<button onclick="swapText();">Click me!</button>
<span id="output2">Hello</span>
<input id="textbox2" type="text" value="Goodbye" />
function swapText() {
	var span = document.getElementById("output2");
	var textBox = document.getElementById("textbox2");
	var temp = span.innerHTML;
	span.innerHTML = textBox.value;
	textBox.value = temp;
}
Hello

8.2 - 8.4: JavaScript Syntax

Comments (same as Java)

// single-line comment

/* multi-line comment */

Number type

var enrollment = 99;
var medianGrade = 2.8;
var credits = 5 + 4 + (2 * 3);

String type

var s = "Connie Client";
var fName = s.substring(0, s.indexOf(" "));   // "Connie"
var len = s.length;                           // 13
var s2 = 'Melvin Merchant';                   // can use "" or ' '

More about String

for loop (same as Java)

for (initialization; condition; update) {
	statements;
}
var sum = 0;
for (var i = 0; i < 100; i++) {
	sum = sum + i;
}
var s1 = "hello";
var s2 = "";
for (var i = 0; i < s.length; i++) {
	s2 += s1.charAt(i) + s1.charAt(i);
}
// s2 stores "hheelllloo"

Math object

var rand1to10 = Math.floor(Math.random() * 10 + 1);
var three = Math.floor(Math.PI);

Special values: null and undefined

var ned = null;
var benson = 9;
var caroline;

// at this point in the code,
//   ned is null
//   benson's 9
//   caroline is undefined

Logical operators

if/else statement (same as Java and c#)

if (condition) { 
	statements;
} else if (condition) {
	statements;
} else {
	statements;
}

Boolean type

var iLike190M = true;
var ieIsGood = "IE6" > 0;   // false
if ("web dev is great") {  /* true */ }
if (0) {  /* false */ }

while loops (same as Java)

while (condition) {
	statements;
}
do {
	statements;
} while (condition);

Popup boxes

alert("message");     // message
confirm("message");   // returns true or false
prompt("message");    // returns user input string
alert confirm prompt

Arrays

var name = [];                          // empty array
var name = [value, value, ..., value];   // pre-filled
name[index] = value;                     // store element
var ducks = ["Huey", "Dewey", "Louie"];

var stooges = [];        // stooges.length is 0
stooges[0] = "Larry";    // stooges.length is 1
stooges[1] = "Moe";      // stooges.length is 2
stooges[4] = "Curly";    // stooges.length is 5
stooges[4] = "Shemp";    // stooges.length is 5

Array methods

var a = ["Stef", "Jason"];   // Stef, Jason
a.push("Brian");             // Stef, Jason, Brian
a.unshift("Kelly");          // Kelly, Stef, Jason, Brian
a.pop();                     // Kelly, Stef, Jason
a.shift();                   // Stef, Jason
a.sort();                    // Jason, Stef

Splitting strings: split and join

var s = "the quick brown fox";
var a = s.split(" ");          // ["the", "quick", "brown", "fox"]
a.reverse();                   // ["fox", "brown", "quick", "the"]
s = a.join("!");               // "fox!brown!quick!the"

DOM element objects

dom object

DOM object properties

<div id="main" class="foo bar">
	<p>Hello, <em>very</em> happy to see you!</p>
	<img id="icon" src="images/borat.jpg" alt="Borat" />
</div>
Property Description Example
tagName element's HTML tag document.getElementById("main").tagName is "DIV"
className CSS classes of element document.getElementById("main").className is "foo bar"
innerHTML content inside element document.getElementById("main").innerHTML is "\n <p>Hello, <em>ve...
src URL target of an image document.getElementById("icon").src is "images/borat.jpg"

DOM properties for form controls

<input id="sid" type="text" size="7" maxlength="7" />
<input id="frosh" type="checkbox" checked="checked" /> Freshman?
Property Description Example
value the text in an input control document.getElementById("sid").value could be "1234567"
checked whether a box is checked document.getElementById("frosh").checked is true
disabled whether a control is disabled (boolean) document.getElementById("frosh").disabled is false
readOnly whether a text box is read-only document.getElementById("sid").readOnly is false

Modifying text inside an element

var paragraph = document.getElementById("welcome");
paragraph.innerHTML = "Welcome to our site!";  // change text on page

DOM element objects have the following properties:

Abuse of innerHTML

// bad style!
var paragraph = document.getElementById("welcome");
paragraph.innerHTML = "<p>text and <a href="page.html">link</a>";

Adjusting styles with the DOM

<button id="clickme">Color Me</button>
window.onload = function() {
	document.getElementById("clickme").onclick = changeColor;
};
function changeColor() {
	var clickMe = document.getElementById("clickme");
	clickMe.style.color = "red";
}
Property Description
style lets you set any CSS style property for an element

Common DOM styling errors

Unobtrusive styling

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

JavaScript in HTML body (example)

<script type="text/javascript">
	JavaScript code
</script>

Injecting Dynamic Text: document.write

document.write("message");

The typeof function

typeof(value)

The arguments array

function example() {
	for (var i = 0; i < arguments.length; i++) {
		alert(arguments[i]);
	}
}
example("how", "are", "you");   // alerts 3 times

The "for each" loop

for (var name in arrayOrObject) {
	do something with arrayOrObject[name];
}

Arrays as maps

var map = [];
map[42] = "the answer";
map[3.14] = "pi";
map["champ"] = "suns";

Date object

var today = new Date();               // today

var midterm = new Date(2007, 4, 4);   // May 4, 2007

The eval (evil?) function

eval("JavaScript code");
eval("var x = 7; x++; alert(x / 2);");  // alerts 4

Dr. Evil

Debugging JavaScript

Common Errors

Object-oriented JavaScript Features

Creating a new anonymous object

var name = {
	fieldName: value,
	...
	fieldName: value
};
var pt = {
	x: 4,
	y: 3
};
alert(pt.x + ", " + pt.y);

Objects that have behavior (functions/methods)

var name = {
	...
	methodName: function(parameters) {
		statements;
	}
};
var pt = {
	x: 4,  y: 3,
	distanceFromOrigin: function() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	}
};

alert(pt.distanceFromOrigin());   // 5

A poor attempt at a "constructor"

What if we want to create an entire new class, not just one object?

Constructor functions

// Constructs and returns a new Point object.
function Point(xValue, yValue) {
	this.x = xValue;
	this.y = yValue;
	this.distanceFromOrigin = function() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	};
}
var p = new Point(4, -3);

Problems with our constructor

// Constructs and returns a new Point object.
function Point(xValue, yValue) {
	this.x = xValue;
	this.y = yValue;
	this.distanceFromOrigin = function() {
		return Math.sqrt(this.x * this.x + this.y * this.y);
	};
}

A paradigm shift: prototypes

prototypes

An object's prototype chain

prototype chain

Constructors and prototypes

// also causes Point.prototype to become defined
function Point(xValue, yValue) {
	...
}

Modifying a prototype

// adding a method to the prototype
className.prototype.methodName = function(parameters) {
	statements;
}
Point.prototype.distanceFromOrigin = function() {
	return Math.sqrt(this.x * this.x + this.y * this.y);
};

Point prototype methods

// Computes the distance between this point and the given point p.	
Point.prototype.distance = function(p) {
	var dx = this.x - p.x;
	var dy = this.y - p.y;
	return Math.sqrt(dx * dx + dy * dy);
};

// Returns a text representation of this object, such as "(3, -4)".	
Point.prototype.toString = function() {
	return "(" + this.x + ", " + this.y + ")";
};

Modifying built-in prototypes

// add a 'contains' method to all String objects
String.prototype.contains = function(text) {
	return this.indexOf(text) >= 0;
};

// add a 'lightUp' method to all HTML DOM element objects
HTMLElement.prototype.lightUp = function() {
	this.style.backgroundColor = "yellow";
	this.style.fontWeight = "bold";
};

Pseudo-inheritance with prototypes

function SuperClassName(parameters) {   // "superclass" constructor
	...
};
function SubClassName(parameters) {     // "subclass" constructor
	...
};
SubClassName.prototype = new SuperClassName(parameters);   // connect them

Pseudo-inheritance example

// Constructor for Point3D "class"
function Point3D(x, y, z) {
	this.x = x;
	this.y = y;
	this.z = z;
};

Point3D.prototype = new Point(0, 0);   // set as "subclass" of Point

// override distanceFromOrigin method
Point3D.prototype.distanceFromOrigin = function() {
	return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
};

12.1: Global DOM Objects

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.event = function;
<button id="ok">OK</button>
document.getElementById("ok").onclick = okayClick;

When does my code run?

	<head>
		<script src="myfile.js" type="text/javascript"></script>
	</head>

	<body> ... </body>
// 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

	<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: document.getElementById("ok") is 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

<!-- look Ma, no JavaScript! -->
<button id="ok">OK</button>
// 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

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");
	};
};

12.2: DOM Element Objects

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

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

12.3: The DOM Tree

Traversing the DOM tree

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>

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 = 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>

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.getElementById(document.createElement("p"));
p.innerHTML = "A paragraph!";
document.getElementById("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.remove(bullets[i]);
		}
	}
}

DOM versus innerHTML hacking

Why not just code the previous example this way?

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

Homework 6

on the homework page