Web Programming Step by Step

Lecture 13
Unobtrusive JavaScript

Reading: 8.1 - 8.2

Except where otherwise noted, the contents of this presentation are Copyright 2010 Marty Stepp and Jessica Miller.

Valid XHTML 1.1 Valid CSS!

8.1: Global DOM Objects

The six global DOM objects

Every Javascript program can refer to the following global objects:

namedescription
document current HTML page and its content
history list of pages the user has visited
location URL of the current HTML page
navigator info about the web browser you are using
screen info about the screen area occupied by the browser
window the browser window

The window object

the entire browser window; the top-level object in DOM hierarchy

The document object

the current web page and the elements inside it

The location object

the URL of the current web page

The navigator object

information about the web browser application

The screen object

information about the client's display screen

The history object

the list of sites the browser has visited in this window

Unobtrusive JavaScript (8.1.1)

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>
$("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
$("ok").onclick = okayClick;   // error: $("ok") is null

The window.onload event (8.1.1)

// just declaring this function now; it doesn't execute yet
function functionName() {
	element.event = functionName;
	element.event = functionName;
	...
}

// tell the browser to run functionName as soon as the HTML
// has finished loading
window.onload = functionName;

An unobtrusive event handler

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

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

window.onload = pageLoad;  // global code

Common unobtrusive JS errors

Anonymous functions (8.1.2)

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

Anonymous vs. named functions

The following are exactly equivalent:

var foo = function() {
   // ...
};
function foo() {
   // ...
}

In either case we can use the function names like variables, executing the function only when parentheses are added:

var bar = foo;
// the following runs the same function twice
foo();
bar();

The keyword this (8.1.3)

this.fieldName                  // access field
this.fieldName = value;          // modify field

this.methodName(parameters);    // call method

Event handler binding

function pageLoad() {
	$("ok").onclick = okayClick;   // bound to okButton here
}

function okayClick() {           // okayClick knows what DOM object
	this.innerHTML = "booyah";     // it was called on
}

window.onload = pageLoad;

Fixing redundant code with this

<fieldset>
	<label><input type="radio" name="ducks" value="Huey"  /> Huey</label>
	<label><input type="radio" name="ducks" value="Dewey" /> Dewey</label>
	<label><input type="radio" name="ducks" value="Louie" /> Louie</label>
</fieldset>
function processDucks() {
	if ($("huey").checked) {
		alert("Huey is checked!");
	} else if ($("dewey").checked) {
		alert("Dewey is checked!");
	} else {
		alert("Louie is checked!");
	}
	alert(this.value + " is checked!");
}

Common bug: Getting existing styles

this.style.fontSize = this.style.fontSize + 10 + "px";            // bad!