<!--#include virtual="commontop.html" -->
<title>Web Programming Step by Step, Lecture 14: Unobtrusive JavaScript and Timers</title>
</head>
<body>
<div class="layout">
<div id="controls"><!-- DO NOT EDIT --></div>
<div id="currentSlide"><!-- DO NOT EDIT --></div>
<div id="header"></div>
<div id="footer">
<h1><em>Web Programming Step by Step</em>, Lecture 14</h1>
<h2>Unobtrusive JavaScript and Timers</h2>
</div>
</div>
<div class="presentation">
<div class="slide">
<h1><a href="http://www.webstepbook.com/">Web Programming Step by Step</a></h1>
<h3>Lecture 14 <br /> Unobtrusive JavaScript and Timers</h3>
<h4>Reading: 7.2 - 7.3; 8.1 - 8.2; 9.2.6</h4>
<p class="license">
Except where otherwise noted, the contents of this presentation are Copyright 2010 Marty Stepp and Jessica Miller.
</p>
<div class="w3c">
<a href="http://validator.w3.org/check/referer"><img src="images/w3c-xhtml11.png" alt="Valid XHTML 1.1" /></a>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="images/w3c-css.png" alt="Valid CSS!" /></a>
</div>
</div>
<div class="slide">
<h1>Problems with JavaScript</h1>
<p>
JavaScript is a powerful language, but it has many flaws:
</p>
<ul>
<li>the DOM can be clunky to use</li>
<li>the same code doesn't always work the same way in every browser
<ul>
<li>code that works great in Firefox, Safari, ... will fail in IE and vice versa</li>
</ul>
</li>
<li>many developers work around these problems with hacks (checking if browser is IE, etc.)
</li>
</ul>
</div>
<div class="slide">
<h1>
<a href="http://prototypejs.org/">Prototype</a> framework
</h1>
<pre class="examplecode js" style="font-size: smaller">
<script <em>src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"</em>
type="text/javascript"></script>
</pre>
<ul>
<li>the <a href="http://prototypejs.org/">Prototype</a> JavaScript library adds many useful features to JavaScript:
<ul>
<li>many useful <a class="popup" href="http://prototypejs.org/learn/extensions">extensions to the DOM</a></li>
<li>added methods to String, Array, Date, Number, Object</li>
<li>improves event-driven programming</li>
<li>many cross-browser compatibility fixes</li>
<li>makes <a class="popup" href="http://prototypejs.org/learn/introduction-to-ajax">Ajax programming</a> easier (seen later)</li>
</ul>
</li>
</ul>
</div>
<div class="slide">
<h1>
The <a href="http://www.prototypejs.org/api/utility/dollar"><code>$</code></a> function
<span class="readingsection">(9.1.3)</span>
</h1>
<pre class="syntaxtemplate js">
$("<var>id</var>")
</pre>
<ul>
<li>
returns the DOM object representing the element with the given <code>id</code>
</li>
<li>
short for <code>document.getElementById("<var>id</var>")</code>
</li>
<li>
often used to write more concise DOM code:
<pre class="examplecode js">
$("footer").innerHTML = $("username").value.toUpperCase();
</pre>
</li>
</ul>
</div>
<div class="slide">
<h1>
Unobtrusive JavaScript
<span class="readingsection">(8.1.1)</span>
</h1>
<ul>
<li>JavaScript event code seen previously was <em>obtrusive</em>, in the HTML; this is bad style</li>
<li>now we'll see how to write <a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript"><em>unobtrusive</em> JavaScript</a> code
<ul>
<li>HTML with minimal JavaScript inside</li>
<li>uses the DOM to attach and execute all JavaScript functions</li>
</ul>
</li>
<li>allows <a href="http://alistapart.com/articles/behavioralseparation">separation</a> of web site into 3 major categories:
<ul>
<li><span class="term">content</span> (HTML) - what is it?</li>
<li><span class="term">presentation</span> (CSS) - how does it look?</li>
<li><span class="term">behavior</span> (JavaScript) - how does it respond to user interaction?</li>
</ul>
</li>
</ul>
</div>
<div class="slide">
<h1>Obtrusive event handlers (bad)</h1>
<div class="example">
<pre class="examplecode html">
<button <em class="bad">onclick="okayClick();"</em>>OK</button>
</pre>
<pre class="examplecode js">
<span class="comment">// called when OK button is clicked</span>
function okayClick() {
alert("booyah");
}
</pre>
<div class="exampleoutput insertoutput"></div>
</div>
<ul>
<li>this is bad style (HTML is cluttered with JS code)</li>
<li>goal: remove all JavaScript code from the HTML body</li>
</ul>
</div>
<div class="slide">
<h1>Attaching an event handler in JavaScript code</h1>
<pre class="syntaxtemplate js">
<span class="comment">// where <var>element</var> is a DOM element object</span>
<var>element</var>.<var>event</var> = <var>function</var>;
</pre>
<div class="example">
<pre class="examplecode html">
<button <em>id="ok"</em>>OK</button>
</pre>
<pre class="examplecode js">
$("ok").<em>onclick</em> = <em>okayClick</em>;
</pre>
<div class="exampleoutput insertoutput"></div>
</div>
<ul>
<li>it is legal to attach event handlers to elements' DOM objects in your JavaScript code
<ul>
<li>
notice that you do <strong>not</strong> put parentheses after the function's name
</li>
</ul>
</li>
<li>this is better style than attaching them in the HTML</li>
<li>Where should we put the above code?</li>
</ul>
</div>
<div class="slide">
<h1>When does my code run?</h1>
<div class="example">
<pre class="examplecode html">
<head>
<em><script src="myfile.js" type="text/javascript"></script></em>
</head>
<body> ... </body>
</pre>
<pre class="examplecode examplecode2 examplecodelast js">
<span class="comment">// global code</span>
var x = 3;
function f(n) { return n + 1; }
function g(n) { return n - 1; }
x = f(x);
</pre>
</div>
<ul>
<li>your file's JS code runs the moment the browser loads the <code>script</code> tag
<ul>
<li>
any variables are declared immediately
</li>
<li>
any functions are declared but not called, unless your global code explicitly calls them
</li>
</ul>
</li>
<li class="incremental">at this point in time, the browser has not yet read your page's <code>body</code>
<ul>
<li>
none of the DOM objects for tags on the page have been created yet
</li>
</ul>
</li>
</ul>
</div>
<div class="slide">
<h1>A failed attempt at being unobtrusive</h1>
<div class="example">
<pre class="examplecode html">
<head>
<em><script src="myfile.js" type="text/javascript"></script></em>
</head>
<body>
<div><button id="ok">OK</button></div>
</pre>
<pre class="examplecode examplecode2 examplecodelast js">
<span class="comment">// global code</span>
<em class="bad">$("ok").onclick = okayClick;</em> <span class="comment">// error: $("ok") is null</span>
</pre>
</div>
<ul>
<li>problem: global JS code runs the moment the script is loaded</li>
<li>script in <code>head</code> is processed before page's <code>body</code> has loaded
<ul>
<li>no elements are available yet or can be accessed yet via the DOM</li>
</ul>
</li>
<li>we need a way to attach the handler after the page has loaded...</li>
</ul>
</div>
<div class="slide">
<h1>
The <code>window.onload</code> event
<span class="readingsection">(8.1.1)</span>
</h1>
<pre class="syntaxtemplate js">
<span class="comment">// this will run once the page has finished loading</span>
function <var>functionName</var>() {
<var>element</var>.<var>event</var> = <var>functionName</var>;
<var>element</var>.<var>event</var> = <var>functionName</var>;
...
}
<em>window.onload = <var>functionName</var>;</em> <span class="comment">// global code</span>
</pre>
<ul>
<li>we want to attach our event handlers right after the page is done loading</li>
<ul>
<li>there is a global event called <code>window.onload</code> event that occurs at that moment</li>
</ul>
<li>in <code>window.onload</code> handler we attach all the other handlers to run when events occur</li>
</ul>
</div>
<div class="slide">
<h1>An unobtrusive event handler</h1>
<div class="example">
<pre class="examplecode html">
<span class="comment"><!-- look Ma, no JavaScript! --></span>
<button id="ok">OK</button>
</pre>
<pre class="examplecode examplecode2 js">
<span class="comment">// called when page loads; sets up event handlers</span>
function pageLoad() {
$("ok").onclick = okayClick;</em>
}
function okayClick() {
alert("booyah");
}
<em>window.onload = pageLoad;</em> <span class="comment">// global code</span>
</pre>
<div class="exampleoutput">
<button onclick="alert('booyah');">OK</button>
</div>
</div>
</div>
<div class="slide">
<h1>Common unobtrusive JS errors</h1>
<ul>
<li>many students mistakenly write <code>()</code> when attaching the handler
<pre class="examplecode js">
<del>window.onload = pageLoad();</del>
window.onload = <em>pageLoad</em>;
<del>okButton.onclick = okayClick();</del>
okButton.onclick = <em>okayClick</em>;
</pre>
<ul>
<li>our <span class="term">JSLint</span> checker will catch this mistake</li>
</ul>
</li>
<li>event names are all lowercase, not capitalized like most variables
<pre class="examplecode js">
<del>window.onLoad = pageLoad;</del>
window.<em>onload</em> = pageLoad;
</pre>
</li>
</ul>
</div>
<div class="slide">
<h1>
Anonymous functions
<span class="readingsection">(8.1.2)</span>
</h1>
<pre class="syntaxtemplate js">
function(<var>parameters</var>) {
<var>statements</var>;
}
</pre>
<ul>
<li>JavaScript allows you to declare <span class="term">anonymous functions</span></li>
<li>quickly creates a function without giving it a name</li>
<li>can be stored as a variable, attached as an event handler, etc.</li>
</ul>
</div>
<div class="slide">
<h1>Anonymous function example</h1>
<div class="example">
<pre class="examplecode js">
window.onload = <em>function() {</em>
var okButton = document.getElementById("ok");
okButton.onclick = okayClick;
<em>};</em>
function okayClick() {
alert("booyah");
}
</pre>
<div class="exampleoutput">
<button onclick="alert('booyah');">OK</button>
</div>
</div>
<ul>
<li>or the following is also legal (though harder to read and bad style):</li>
</ul>
<pre class="examplecode js">
window.onload = <em>function() {</em>
var okButton = document.getElementById("ok");
okButton.onclick = <em>function() {</em>
alert("booyah");
<em>};</em>
<em>};</em>
</pre>
</div>
<div class="slide">
<h1>
Unobtrusive styling
<span class="readingsection">(8.2.3)</span>
</h1>
<pre class="examplecode js">
function okayClick() {
<del>this.style.color = "red";</del>
this.<em>className = "highlighted"</em>;
}
</pre>
<pre class="examplecode css">
.<em>highlighted</em> { color: red; }
</pre>
<ul>
<li>well-written JavaScript code should contain as little CSS as possible</li>
<li>use JS to set CSS classes/IDs on elements</li>
<li>define the styles of those classes/IDs in your CSS file</li>
</ul>
</div>
<div class="slide">
<h1>
Timer events
<span class="readingsection">(9.2.6)</span>
</h1>
<div class="topfigure" style="width: 12%">
<img src="images/timer.gif" alt="timer" style="width: 100%" />
</div>
<table class="standard">
<tr>
<th>
method
</th>
<th>
description
</th>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/htmldom/met_win_settimeout.asp">setTimeout</a>(<var>function</var>, <var>delayMS</var>);</code>
</td>
<td>
arranges to call given function after given delay in ms
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/htmldom/met_win_setinterval.asp">setInterval</a>(<var>function</var>, <var>delayMS</var>);</code>
</td>
<td>
arranges to call function repeatedly every <var>delayMS</var> ms
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/htmldom/met_win_cleartimeout.asp">clearTimeout</a>(<var>timerID</var>);</code> <br />
<code><a href="http://www.w3schools.com/htmldom/met_win_clearinterval.asp">clearInterval</a>(<var>timerID</var>);</code>
</td>
<td>
stops the given timer so it will not call its function
</td>
</tr>
</table>
<ul>
<li>
both <code>setTimeout</code> and <code>setInterval</code> return an ID representing the timer
<ul>
<li>
this ID can be passed to <code>clearTimeout</code>/<code>Interval</code> later to stop the timer
</li>
</ul>
</li>
</ul>
</div>
<div class="slide">
<h1>
<code>setTimeout</code></a> example</a>
</h1>
<div class="example">
<pre class="examplecode html">
<button <em>onclick="delayMsg();"</em>>Click me!</button>
<span <em>id="output"</em>></span>
</pre>
<pre class="examplecode examplecode2 js">
function delayMsg() {
<em>setTimeout(booyah, 5000)</em>;
$("output").innerHTML = "Wait for it...";
}
function booyah() { <span class="comment">// called when the timer goes off</span>
$("output").innerHTML = "BOOYAH!";
}
</pre>
<div class="exampleoutput">
<button onclick="document.getElementById('output').innerHTML = 'Wait for it...'; setTimeout("document.getElementById('output').innerHTML = 'BOOYAH!';", 5000)">Click me!</button>
<span id="output"></span>
</div>
</div>
</div>
<div class="slide">
<h1>
<code>setInterval</code> example
</h1>
<div class="example">
<pre class="examplecode examplecode2 js">
<em>var timer = null;</em> <span class="comment">// stores ID of interval timer</span>
function delayMsg2() {
if (timer == null) {
<em>timer = setInterval(rudy, 1000)</em>;
} else {
<em>clearInterval(timer)</em>;
timer = null;
}
}
function rudy() { <span class="comment">// called each time the timer goes off</span>
$("output").innerHTML += " Rudy!";
}
</pre>
<div class="exampleoutput">
<script type="text/javascript">
window.timer = null;
window.delayMsg2 = function() {
if (timer == null) {
timer = setInterval(rudy, 1000);
} else {
clearInterval(timer);
timer = null;
}
};
window.rudy = function() {
document.getElementById("output2").innerHTML += " Rudy!";
};
</script>
<button onclick="delayMsg2();">Click me!</button>
<span id="output2"></span>
</div>
</div>
</div>
<div class="slide">
<h1>Passing parameters to timers</a></h1>
<div class="example">
<pre class="examplecode js">
function delayedMultiply() {
<span class="comment">// 6 and 7 are passed to multiply when timer goes off</span>
setTimeout(multiply, 2000<em>, 6, 7</em>);
}
function multiply(<em>a, b</em>) {
alert(a * b);
}
</pre>
<div class="exampleoutput insertoutput">
<button onclick="delayedMultiply();">Click me</button>
</div>
</div>
<ul>
<li>any parameters after the delay are eventually passed to the timer function
<ul>
<li>doesn't work in IE6; must create an intermediate function to pass the parameters</li>
</ul>
</li>
<li>
why not just write this?
<pre class="examplecode js">
setTimeout(<em>multiply(6 * 7)</em>, 2000);
</pre>
</li>
</ul>
</div>
<div class="slide">
<h1>Common timer errors</h1>
<ul>
<li>
many students mistakenly write <code>()</code> when passing the function
<pre class="examplecode js">
<del>setTimeout(booyah(), 2000);</del>
setTimeout(<em>booyah</em>, 2000);
<del>setTimeout(multiply(num1 * num2), 2000);</del>
setTimeout(<em>multiply</em>, 2000<em>, num1, num2</em>);
</pre>
<ul>
<li>what does it actually do if you have the <code>()</code> ?</li>
<li class="incremental">it calls the function immediately, rather than waiting the 2000ms!</li>
</ul>
</li>
</ul>
</div>
<!--#include virtual="commonbottom.html" -->