Download as pdf or txt
Download as pdf or txt
You are on page 1of 214

JavaScript Basics

In this lesson of the JavaScript tutorial, you will learn...

1. To work with the HTML DOM.


2. To follow JavaScript syntax rules.
3. To write JavaScript inline.
4. To write JavaScript in script blocks.
5. To create and link to external JavaScript files.
6. To work with JavaScript objects, methods, and properties.
7. To reference HTML elements with JavaScript.
8. To use event handlers.

The Name "JavaScript"


In this manual, we refer to the language we are learning as JavaScript, which is what it is usually called. However, the
name JavaScript is owned by Netscape. Microsoft calls its version of the language JScript. The generic name of the
language is EcmaScript.

The HTML DOM


The HTML Document Object Model (DOM) is the browser's view of an HTML page as an object hierarchy, starting
with the browser window itself and moving deeper into the page, including all of the elements on the page and their

attributes. Below is a simplified version of the HTML DOM.

As shown, the top-level object is window. The document object is a child of window and all the objects (i.e, elements)
that appear on the page (e.g, forms, links, images, tables, etc.) are descendants of the document object. These objects
can have children of their own. For example, form objects generally have several child objects, including textboxes,
radio buttons, and select menus.

JavaScript Syntax
Basic Rules

1. JavaScript statements end with semi-colons.


2. JavaScript is case sensitive.
3. JavaScript has two forms of comments:
o Single-line comments begin with a double slash (//).
o Multi-line comments begin with "/*" and end with "*/".

Syntax
// This is a single-line comment

/*
This is
a multi-line
comment.
*/

Dot Notation
In JavaScript, objects can be referenced using dot notation, starting with the highest-level object (i.e, window). Objects
can be referred to by name or id or by their position on the page. For example, if there is a form on the page named
"loginform", using dot notation you could refer to the form as follows:

Syntax
window.document.loginform

Assuming that loginform is the first form on the page, you could also refer to this way:

Syntax
window.document.forms[0]

A document can have multiple form elements as children. The number in the square brackets ([]) indicates the specific
form in question. In programming speak, every document object contains an array of forms. The length of the array
could be zero (meaning there are no forms on the page) or greater. In JavaScript, arrays are zero-based, meaning that
the first form on the page is referenced with the number zero (0) as shown in the syntax example above.

Square Bracket Notation

Objects can also be referenced using square bracket notation as shown below.

Syntax
window['document']['loginform']

// and

window['document']['forms[0]']

Dot notation and square bracket notation are completely interchangeable. Dot notation is much more common;
however, as we will see later in the course, there are times when it is more convenient to use square bracket notation.

Where Is JavaScript Code Written?


JavaScript code can be written inline (e.g, within HTML tags called event handlers), in script blocks, and in external
JavaScript files. The page below shows examples of all three.

Code Sample: JavaScriptBasics/Demos/JavaScript.html


<html>
<head>
<title>JavaScript Page</title>
<script type="text/javascript">
window.alert("The page is loading");
</script>
</head>
<body>
<p align="center">
<span onclick="document.bgColor = 'red';">Red</span> |
<span onclick="document.bgColor = 'white';">White</span>
</p>
<script type="text/javascript" src="Script.js"></script>
</body>
</html>

Code Sample: JavaScriptBasics/Demos/Script.js


document.write("Hello, there!");
Code Explanation
As this page loads, an alert will pop up that says "The page is loading" as shown below.

After the user clicks the OK button, the page will finish loading and will appear as follows.

The text "Hello, there!" is written dynamically by the code in JavaScriptBasics/Demos/Script.js. We will look at the
code in this file and in JavaScriptBasics/Demos/JavaScript.html again shortly.

JavaScript Objects, Methods and Properties


JavaScript is used to manipulate or get information about objects in the HTML DOM. Objects in an HTML page have
methods (actions, such as opening a new window or submitting a form) and properties (attributes or qualities, such as
color and size).

To illustrate objects, methods and properties, we will look at the code in JavaScriptBasics/Demos/JavaScript2.html, a
slightly modified version of JavaScriptBasics/Demos/JavaScript.html, which we looked at earlier, and at the code in
JavaScriptBasics/Demos/Script2.js.

Code Sample: JavaScriptBasics/Demos/JavaScript2.html


<html>
<head>
<title>JavaScript Page</title>
<script type="text/javascript">
//Pop up an alert
window.alert("The page is loading");
</script>
</head>
<body>
<p align="center">
<span onclick="document.bgColor = 'red';">Red</span> |
<span onclick="document.bgColor = 'white';">White</span> |
<span onclick="document.bgColor = 'green';">Green</span> |
<span onclick="document.bgColor = 'blue';">Blue</span>
</p>
<script type="text/javascript" src="Script2.js"></script>
</body>
</html>

Code Sample: JavaScriptBasics/Demos/Script2.js


/*
This script simply outputs
"Hello, there!"
to the browser.
*/
document.write("Hello, there!");

Methods

Methods are the verbs of JavaScript. They cause things to happen.

window.alert()

HTML pages are read and processed from top to bottom. The JavaScript code in the initial script block at the top of
JavaScriptBasics/Demos/JavaScript2.html calls the alert() method of the window object. When the browser reads that
line of code, it will pop up an alert box and will not continue processing the page until the user presses the OK button.
Once the user presses the button, the alert box disappears and the rest of the page loads.
document.write()

The write() method of the document object is used to write out code to the page as it loads. In
JavaScriptBasics/Demos/Script2.js, it simply writes out "Hello, there!"; however, it is more often used to write out
dynamic data, such as the date and time on the user's machine.

Arguments

Methods can take zero or more arguments separated by commas.

Syntax
object.method(argument1, argument2);

The alert() and write() methods shown in the example above each take only one argument: the message to show.

Properties

Properties are the adjectives of JavaScript. They describe qualities of objects and, in some cases are writable (can be
changed dynamically).

document.bgColor

The bgColor property of the document object is read-write. Looking back at JavaScriptBasics/Demos/JavaScript2.html,
the four span elements use the onclick event handler to catch click events. When the user clicks on a span, JavaScript is
used to change the value of the bgColor property to a new color.

The Implicit window Object

The window object is always the implicit top-level object and therefore does not have to be included in references to
objects. For example, window.document.write() can be shortened to document.write(). Likewise, window.alert() can be
shortened to just alert().

The getElementById() Method

A very common way to reference HTML elements is by their ID using the getElementById() method of the document
object as shown in the example below.

Event Handlers
In JavaScriptBasics/Demos/JavaScript2.html, we used the onclick event handler to call JavaScript code that changed
the background color of the page. Event handlers are attributes that force an element to "listen" for a specific event to
occur. Event handlers all begin with the letters "on". The table below lists the HTML event handlers with descriptions.

HTML Event Handlers


Event Handler Elements Supported Description
onblur a, area, button, input, label, select, textarea the element lost the focus
the element value was
onchange input, select, textarea
changed
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a pointer button was
onclick
head, html, iframe, isindex, meta, param, script, style, title clicked
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a pointer button was
ondblclick
head, html, iframe, isindex, meta, param, script, style, title double clicked
HTML Event Handlers
Event Handler Elements Supported Description
the element received the
onfocus a, area, button, input, label, select, textarea
focus
All elements except applet, base, basefont, bdo, br, font, frame, frameset,
onkeydown a key was pressed down
head, html, iframe, isindex, meta, param, script, style, title
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a key was pressed and
onkeypress
head, html, iframe, isindex, meta, param, script, style, title released
All elements except applet, base, basefont, bdo, br, font, frame, frameset,
onkeyup a key was released
head, html, iframe, isindex, meta, param, script, style, title
all the frames have been
onload frameset
loaded
the document has been
onload body
loaded
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a pointer button was
onmousedown
head, html, iframe, isindex, meta, param, script, style, title pressed down
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a pointer was moved
onmousemove
head, html, iframe, isindex, meta, param, script, style, title within
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a pointer was moved
onmouseout
head, html, iframe, isindex, meta, param, script, style, title away
All elements except applet, base, basefont, bdo, br, font, frame, frameset,
onmouseover a pointer was moved onto
head, html, iframe, isindex, meta, param, script, style, title
All elements except applet, base, basefont, bdo, br, font, frame, frameset, a pointer button was
onmouseup
head, html, iframe, isindex, meta, param, script, style, title released
onreset form the form was reset
onselect input, textarea some text was selected
onsubmit form the form was submitted
all the frames have been
onunload frameset
removed
the document has been
onunload body
removed

Exercise: Using Event Handlers

Duration: 15 to 25 minutes.

In this exercise, you will use some of the event handlers from the table above to allow the user to change the
background color of the page.

1. Open JavaScriptBasics/Exercises/JavaScript.html for editing.


2. Modify the page so that...
o when it is finished loading an alert pops up reading "The page has loaded!"
o when the "Red" button is clicked, the background color turns red and an alert pops up reading "The
background color is now Red."
o when the "Green" button is double-clicked, the background color turns green and an alert pops up
reading "The background color is now Green."
o when the "Orange" button is clicked down, the background color turns orange and an alert pops up
reading "The background color is now Orange."
o when the mouse button is released over the "Blue" button, the background color turns blue and an
alert pops up reading "The background color is now Blue."

Code Sample: JavaScriptBasics/Exercises/JavaScript.html


<html>
<head>
<title>JavaScript Page</title>
<script type="text/javascript">
window.alert("The page is loading.");
</script>
</head>
<body>
<form>
Click the button to turn the page
<input type="button" value="Red"/>
<br/><br/>
Double click the button to turn the page
<input type="button" value="Green"/>
<br/><br/>
Click down on the button to turn the page
<input type="button" value="Orange"/>
<br/><br/>
Release the mouse while on the button to turn the page
<input type="button" value="Blue"/>
</form>
<hr/>
<script type="text/javascript" src="Script.js"></script>
</body>
</html>

1. Add functionality so that when the user presses any key, the background color turns white.
2. Add a "Black" button. When the user hovers over this button and presses the mouse button down, the
background color should turn black. When the user releases the mouse button, the background color should
turn white.

Where is the solution?

JavaScript Basics Conclusion


In this lesson of the JavaScript tutorial, you have learned the basics of JavaScript. Now you're ready for more.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Variables, Arrays and Operators
In this lesson of the JavaScript tutorial, you will learn...

1. To create, read and modify JavaScript variables.


2. To work with JavaScript arrays.
3. To work with JavaScript operators.

JavaScript Variables
Variables are used to hold data in memory. JavaScript variables are declared with the var keyword.

var age;

Multiple variables can be declared in a single step.

var age, height, weight, gender;

After a variable is declared, it can be assigned a value.

age = 34;

Variable declaration and assignment can be done in a single step.

var age = 34;

A Loosely-typed Language

JavaScript is a loosely-typed language. This means that you do not specify the data type of a variable when declaring it.
It also means that a single variable can hold different data types at different times and that JavaScript can change the
variable type on the fly. For example, the age variable above is an integer. However, the variable strAge below would
be a string (text) because of the quotes.

var strAge = "34";

If you were to try to do a math function on strAge (e.g, multiply it by 4), JavaScript would dynamically change it to an
integer. Although this is very convenient, it can also cause unexpected results, so be careful.

Storing User-Entered Data

The following example uses the prompt() method of the window object to collect user input. The value entered by the
user is then assigned to a variable, which is accessed when the user clicks on one of the span elements.

Code Sample: VariablesArraysOperators/Demos/Variables.html


<html>
<head>
<title>JavaScript Variables</title>
<script type="text/javascript">
//Pop up a prompt
var USER_COLOR = window.prompt("Enter a color.", "");
</script>
</head>
<body>
<p align="center">
<span onclick="document.bgColor = 'red';">Red</span> |
<span onclick="document.bgColor = 'white';">White</span> |
<span onclick="document.bgColor = 'green';">Green</span> |
<span onclick="document.bgColor = 'blue';">Blue</span> |
<span onclick="document.bgColor = USER_COLOR;">
<script type="text/javascript">
document.write(USER_COLOR);
</script>
</span>
</p>
</body>
</html>
Code Explanation

As the page loads, a prompt pops up asking the user to enter a color.

This is done with the prompt() method of the window object. The prompt() method is used to get input from the user. It
takes two arguments:

1. The message in the dialog box (e.g., "Enter a color.").


2. The default value that appears in the text box. In the example above this is an empty string (e.g, "").

If the OK button is pressed, the prompt returns the value entered in the textbox. If the Cancel button or the close button
(the red X) is pressed, the prompt returns null. The line below assigns whatever is returned to the variable
USER_COLOR.

var USER_COLOR = window.prompt("Enter a color.", "");

A script block with a call to document.write() is then used to output the color entered by the user. This output is
contained within a span element, which has an onclick event handler that will be used to turn the background color of
the page to the user-entered color.

<span onclick="document.bgColor = USER_COLOR;">


<script type="text/javascript">
document.write(USER_COLOR);
</script>
</span>

Exercise: Using Variables

Duration: 5 to 15 minutes.

In this exercise, you will practice using variables.

1. Open VariablesArraysOperators/Exercises/Variables.html for editing.


2. Below the ADD PROMPT HERE comment, write code that will prompt the user for her first name and
assign the result to a variable.
3. Add a button below the Ringo button that reads "Your Name". Add functionality so that when this button is
pressed an alert pops up showing the user's first name.
4. Test your solution in a browser.

Code Sample: VariablesArraysOperators/Exercises/Variables.html


<html>
<head>
<title>JavaScript Variables</title>
<script type="text/javascript">
//ADD PROMPT HERE
</script>
</head>
<body>
<form>
<input type="button" value="Paul"
onclick="alert('Paul');"/>
<br/><br/>
<input type="button" value="John"
onclick="alert('John');"/>
<br/><br/>
<input type="button" value="George"
onclick="alert('George');"/>
<br/><br/>
<input type="button" value="Ringo"
onclick="alert('Ringo');"/>
<br/><br/>
<!--ADD BUTTON HERE-->
</form>
</body>
</html>
Where is the solution?

Arrays
An array is a grouping of objects that can be accessed through subscripts. At its simplest, an array can be thought of as
a list. In JavaScript, the first element of an array is considered to be at position zero (0), the second element at position
one (1), and so on. Arrays are useful for storing data of similar types.

Arrays are declared using the new keyword.

var myarray = new Array();

It is also possible and very common to use the [] literal to declare a new Array object.

var myarray = [];

Values are assigned to arrays as follows.

myarray[0] = value1;
myarray[1] = value2;
myarray[2] = value3;

Arrays can be declared with initial values.

var myarray = new Array(value1, value2, value3);


//or, using the [] notation:
var myarray = [value1, value2, value3];

The following example is similar to the previous one, except that it prompts the user for four different colors and places
each into the USER_COLORS array. It then displays the values in the USER_COLORS array in the spans and assigns
them to document.bgColor when the user clicks on the spans.

Unlike in some languages, values in JavaScript arrays do not all have to be of the same data type.

Code Sample: VariablesArraysOperators/Demos/Arrays.html


<html>
<head>
<title>JavaScript Arrays</title>
<script type="text/javascript">
//Pop up four prompts and create an array
var USER_COLORS = new Array();
USER_COLORS[0] = window.prompt("Choose a color.", "");
USER_COLORS[1] = window.prompt("Choose a color.", "");
USER_COLORS[2] = window.prompt("Choose a color.", "");
USER_COLORS[3] = window.prompt("Choose a color.", "");
</script>
</head>
<body>
<p align="center">
<span onclick="document.bgColor = USER_COLORS[0];">
<script type="text/javascript">
document.write(USER_COLORS[0]);
</script>
</span> |
<span onclick="document.bgColor = USER_COLORS[1];">
<script type="text/javascript">
document.write(USER_COLORS[1]);
</script>
</span> |
<span onclick="document.bgColor = USER_COLORS[2];">
<script type="text/javascript">
document.write(USER_COLORS[2]);
</script>
</span> |
<span onclick="document.bgColor = USER_COLORS[3];">
<script type="text/javascript">
document.write(USER_COLORS[3]);
</script>
</span>
</p>
</body>
</html>
Code Explanation

As the page loads, an array called USER_COLORS is declared.

var USER_COLORS = new Array();

The next four lines populate the array with user-entered values.

USER_COLORS[0] = window.prompt("Choose a color.", "");


USER_COLORS[1] = window.prompt("Choose a color.", "");
USER_COLORS[2] = window.prompt("Choose a color.", "");
USER_COLORS[3] = window.prompt("Choose a color.", "");

The body of the page contains a paragraph with four span tags, the text of which is dynamically created with values
from the USER_COLORS array.

Exercise: Working with Arrays

Duration: 15 to 25 minutes.

In this exercise, you will practice working with arrays.

1. Open VariablesArraysOperators/Exercises/Arrays.html for editing.


2. Below the comment, declare a ROCK_STARS array and populate it with four values entered by the user.
3. Add functionality to the buttons, so that alerts pop up with values from the array when the buttons are
clicked.
4. Test your solution in a browser.

Code Sample: VariablesArraysOperators/Exercises/Arrays.html


<html>
<head>
<title>JavaScript Arrays</title>
<script type="text/javascript">
/*
Declare a ROCK_STARS array and populate it with
four values entered by the user.
*/
</script>
</head>
<body>
<form>
<input type="button" value="Favorite"/>
<br/><br/>
<input type="button" value="Next Favorite"/>
<br/><br/>
<input type="button" value="Next Favorite"/>
<br/><br/>
<input type="button" value="Next Favorite"/>
</form>
</body>
</html>
Where is the solution?

Associative Arrays

Whereas regular (or enumerated) arrays are indexed numerically, associative arrays are indexed using names as keys.
The advantage of this is that the keys can be meaningful, which can make it easier to reference an element in an array.
The example below illustrates how an associative array is used.

Code Sample: VariablesArraysOperators/Demos/AssociativeArrays.html


<html>
<head>
<title>JavaScript Arrays</title>
<script type="text/javascript">
var BEATLES = [];
BEATLES["singer1"] = "Paul";
BEATLES["singer2"] = "John";
BEATLES["guitarist"] = "George";
BEATLES["drummer"] = "Ringo";
</script>
</head>
<body>
<p align="center">
<script type="text/javascript">
document.write(BEATLES["singer1"]);
document.write(BEATLES["singer2"]);
document.write(BEATLES["guitarist"]);
document.write(BEATLES["drummer"]);
</script>
</p>
</body>
</html>

Array Properties and Methods

The tables below show some of the most useful array properties and methods. All of the examples assume an array
called BEATLES that holds "Paul", "John", "George", and "Ringo".

var BEATLES = ["Paul", "John", "George", "Ringo"];


Array Properties
Property Description Example
length Holds the number of elements in an array. BEATLES.length // 4
Array Methods
Property Description Example
Returns a delimited list of the items indexed with integers in BEATLES.join(":") //
join(delimiter)
the array. The default delimiter is a comma. Paul:John:George:Ringo
pop() Removes the last item in an array and returns its value. BEATLES.pop() // Returns Ringo
shift() Removes the first item in an array and returns its value. BEATLES.shift() // Returns Paul
Returns a subarray from start to end. If end is left out, it BEATLES.slice(1 ,2) //Returns [John,
slice(start, end)
includes the remainder of the array. George]
splice(start, Removes count items from start in the array and returns the BEATLES.splice(1, 2) //Returns
count) resulting array. [Paul, Ringo]
JavaScript Operators
Arithmetic Operators
Operator Description
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus (remainder)
++ Increment by one
-- Decrement by one
Assignment Operators
Operator Description
= Assignment
+= One step addition and assignment (a+=3 is the same as a=a+3)
-= One step subtraction and assignment (a-=3 is the same as a=a-3)
*= One step multiplication and assignment (a*=3 is the same as a=a*3)
/= One step division and assignment (a/=3 is the same as a=a/3)
%= One step modulus and assignment (a%=3 is the same as a=a%3)
String Operators
Operator Description
+ Concatenation (var greeting = "Hello " + firstname;)
+= One step concatenation and assignment (var greeting = "Hello "; greeting += firstname;)
Ternary Operator
Operator Description
?: Conditional evaluation (var evenOrOdd = (number % 2 == 0) ? "even" : "odd";)

The following code sample shows these operators in use.

Code Sample: VariablesArraysOperators/Demos/Operators.html


<html>
<head>
<title>JavaScript Operators</title>
<script type="text/javascript">
var USER_NUM1 = window.prompt("Choose a number.", "");
alert("You chose " + USER_NUM1);
var USER_NUM2 = window.prompt("Choose another number.", "");
alert("You chose " + USER_NUM2);
var NUMS_ADDED = USER_NUM1 + Number(USER_NUM2);
var NUMS_SUBTRACTED = USER_NUM1 - USER_NUM2;
var NUMS_MULTIPLIED = USER_NUM1 * USER_NUM2;
var NUMS_DIVIDED = USER_NUM1 / USER_NUM2;
var NUMS_MODULUSED = USER_NUM1 % USER_NUM2;
</script>
</head>
<body>
<p style="text-align:center; font-size:large">
<script type="text/javascript">
document.write(USER_NUM1 + " + " + USER_NUM2 + " = ");
document.write(NUMS_ADDED + "<br/>");
document.write(USER_NUM1 + " - " + USER_NUM2 + " = ");
document.write(NUMS_SUBTRACTED + "<br/>");
document.write(USER_NUM1 + " * " + USER_NUM2 + " = ");
document.write(NUMS_MULTIPLIED + "<br/>");
document.write(USER_NUM1 + " / " + USER_NUM2 + " = ");
document.write(NUMS_DIVIDED + "<br/>");
document.write(USER_NUM1 + " % " + USER_NUM2 + " = ");
document.write(NUMS_MODULUSED + "<br/>");
</script>
</p>
</body>
</html>
Code Explanation

The file above illustrates the use of the concatenation operator and several math operators. It also illustrates a potential
problem with loosely-typed languages. This page is processed as follows:

1. The user is prompted for a number and the result is assigned to USER_NUM1.
2. An alert pops up telling the user what number she entered. The concatenation operator (+) is used to combine
two strings: "You chose " and the number entered by the user. Note that all user-entered data is always
treated as a string of text, even if the text consists of only digits.
3. The user is prompted for another number and the result is assigned to USER_NUM2.
4. Another alert pops up telling the user what number she entered.
5. Five variables are declared and assigned values.
6. var NUMS_ADDED = USER_NUM1 + USER_NUM2;
7. var NUMS_SUBTRACTED = USER_NUM1 - USER_NUM2;
8. var NUMS_MULTIPLIED = USER_NUM1 * USER_NUM2;
9. var NUMS_DIVIDED = USER_NUM1 / USER_NUM2;
var NUMS_MODULUSED = USER_NUM1 % USER_NUM2;

10. The values the variables contain are output to the browser.

So, 5 + 4 is 54! It is when 5 and 4 are strings, and, as stated earlier, all user-entered data is treated as a string. In the
lesson on JavaScript Functions, you will learn how to convert a string to a number.

Exercise: Working with Operators

Duration: 15 to 25 minutes.

In this exercise, you will practice working with JavaScript operators.

1. Open VariablesArraysOperators/Exercises/Operators.html for editing.


2. Add code to prompt the user for the number of CDs she owns of her favorite and second favorite rockstars'.
3. In the body, let the user know how many more of her favorite rockstar's CDs she has than of her second
favorite rockstar's CDs.
4. Test your solution in a browser.

Code Sample: VariablesArraysOperators/Exercises/Operators.html


<html>
<head>
<title>JavaScript Operators</title>
<script type="text/javascript">
var ROCK_STARS = [];
ROCK_STARS[0] = prompt("Who is your favorite rock star?", "");
/*
Ask the user how many of this rockstar's CDs she owns and store
the result in a variable.
*/
ROCK_STARS[1] = prompt("And your next favorite rock star?", "");
/*
Ask the user how many of this rockstar's CDs she owns and store
the result in a variable.
*/
</script>
</head>
<body>
<!--
Let the user know how many more of her favorite rockstar's CDs
she has than of her second favorite rockstar's CDs.
-->
</body>
</html>

1. Open VariablesArraysOperators/Exercises/Operators-challenge.html for editing.

2. Modify it so that it outputs an unordered list as shown below.

Where is the solution?

Variables, Arrays and Operators Conclusion


In this lesson of the JavaScript tutorial, you have learned to work with JavaScript variables, arrays and operators.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
JavaScript Functions
In this lesson of the JavaScript tutorial, you will learn...

1. To work with some of JavaScript's built-in functions.


2. To create your own functions.
3. To return values from functions.

Built-in Functions
JavaScript has a number of built-in functions. We will examine some of them in this section.

Number(object)

The Number() function takes one argument: an object, which it attempts to convert to a number. If it cannot, it returns
NaN, for "Not a Number."

Code Sample: JavaScriptFunctions/Demos/Number.html


<html>
<head>
<title>Number() Function</title>
<script type="text/javascript">
var STR_NUM1 = "1";
var STR_NUM2 = "2";
var STR_SUM = STR_NUM1 + STR_NUM2; //returns 12
alert(STR_SUM);

var INT_NUM1 = Number(STR_NUM1);


var INT_NUM2 = Number(STR_NUM2);
var INT_SUM = INT_NUM1 + INT_NUM2; //returns 3
alert(INT_SUM);
</script>
</head>
<body>
Nothing to show here.
</body>
</html>
Code Explanation

Because STR_NUM1 and STR_NUM2 are both strings, the + operator concatenates them, resulting in "12".

var STR_NUM1 = "1";


var STR_NUM2 = "2";
var STR_SUM = STR_NUM1 + STR_NUM2; //returns 12
alert(STR_SUM);

After the Number() function has been used to convert the strings to numbers, the + operator performs addition,
resulting in 3.

var INT_NUM1 = Number(STR_NUM1);


var INT_NUM2 = Number(STR_NUM2);
var INT_SUM = INT_NUM1 + INT_NUM2; //returns 3
alert(INT_SUM);

String(object)

The String() function takes one argument: an object, which it converts to a string.
Code Sample: JavaScriptFunctions/Demos/String.html
<html>
<head>
<title>String() Function</title>
<script type="text/javascript">
var INT_NUM1 = 1;
var INT_NUM2 = 2;
var INT_SUM = INT_NUM1 + INT_NUM2; //returns 3
alert(INT_SUM);

var STR_NUM1 = String(INT_NUM1);


var STR_NUM2 = String(INT_NUM2);
var STR_SUM = STR_NUM1 + STR_NUM2; //returns 12
alert(STR_SUM);
</script>
</head>
<body>
Nothing to show here.
</body>
</html>
Code Explanation

Because INT_NUM1 and INT_NUM2 are both numbers, the + operator performs addition, resulting in 3.

var INT_NUM1 = 1;
var INT_NUM2 = 2;
var INT_SUM = INT_NUM1 + INT_NUM2; //returns 3
alert(INT_SUM);

After the String() function has been used to convert the numbers to string, the + operator performs concatenation,
resulting in "12".

var STR_NUM1 = String(INT_NUM1);


var STR_NUM2 = String(INT_NUM2);
var STR_SUM = STR_NUM1 + STR_NUM2; //returns 12
alert(STR_SUM);

isNaN(object)

The isNaN() function takes one argument: an object. The function checks if the object is not a number (or cannot be
converted to a number). It returns true if the object is not a number and false if it is a number.

Code Sample: JavaScriptFunctions/Demos/isNaN.html


<html>
<head>
<title>isNaN() Function</title>
</head>
<body>
<table border="1" cellpadding="3" align="center">
<tr>
<th>Function</th><th>Result</th>
</tr>
<script type="text/javascript">
document.write("<tr><td>isNaN(4)</td>");
document.write("<td>" + isNaN(4) + "</td></tr>");
document.write("<tr><td>isNaN(\"4\")</td>");
document.write("<td>" + isNaN("4") + "</td></tr>");
document.write("<tr><td>isNaN(0/0)</td>");
document.write("<td>" + isNaN(0/0) + "</td></tr>");
document.write("<tr><td>isNaN(\"hello\")</td>");
document.write("<td>" + isNaN("hello") + "</td></tr>");
var AGE_STR = "twelve";
document.write("<tr><td>isNaN(AGE_STR)</td>");
document.write("<td>" + isNaN(AGE_STR) + "</td></tr>");
var AGE_INT = 12;
document.write("<tr><td>isNaN(AGE_INT)</td>");
document.write("<td>" + isNaN(AGE_INT) + "</td></tr>");
</script>
</table>
</body>
</html>
Code Explanation

The output will look like this:

parseFloat() and parseInt()

The parseFloat() function takes one argument: a string. If the string begins with a number, the function reads through
the string until it finds the end of the number, hacks off the remainder of the string, and returns the result. If the string
does not begin with a number, the function returns NaN.

The parseInt() function also takes one argument: a string. If the string begins with an integer, the function reads through
the string until it finds the end of the integer, hacks off the remainder of the string, and returns the result. If the string
does not begin with an integer, the function returns NaN.

Code Sample: JavaScriptFunctions/Demos/ParsingNumbers.html


<html>
<head>
<title>Parsing for Numbers</title>
</head>
<body>
<table border="1" cellpadding="3" align="center">
<tr>
<th>Function</th><th>Result</th>
</tr>
<script type="text/javascript">
var RACE = "26.2 miles";
document.write("<tr><td>parseFloat(RACE)</td>");
document.write("<td>" + parseFloat(RACE) + "</td></tr>");
document.write("<tr><td>parseInt(RACE)</td>");
document.write("<td>" + parseInt(RACE) + "</td></tr>");
RACE = "Marathon";
document.write("<tr><td>parseFloat(RACE)</td>");
document.write("<td>" + parseFloat(RACE) + "</td></tr>");
document.write("<tr><td>parseInt(RACE)</td>");
document.write("<td>" + parseInt(RACE) + "</td></tr>");
</script>
</table>
</body>
</html>
Code Explanation

The output will look like this:

Built-in Functions vs. Methods


Methods and functions are similar in that they both make things happen. They are also syntactically similar. The major
difference is that methods are tied to an object; whereas, functions are not. For example, alert() is a method of the
window object; whereas parseInt() is a standalone function.

Exercise: Working with Built-in Functions

Duration: 15 to 25 minutes.

In this exercise, you will practice working with JavaScript's built-in functions.
1. Open JavaScriptFunctions/Exercises/BuiltinFunctions.html for editing.
2. Modify the file so that it outputs the sum of the two numbers entered by the user.

Code Sample: JavaScriptFunctions/Exercises/BuiltinFunctions.html


<html>
<head>
<title>JavaScript Operators</title>
<script type="text/javascript">
var USER_NUM1, USER_NUM2, NUMS_ADDED;
USER_NUM1 = window.prompt("Choose a number.", "");
alert("You chose " + USER_NUM1);
USER_NUM2 = window.prompt("Choose another number.", "");
alert("You chose " + USER_NUM2);
NUMS_ADDED = USER_NUM1 + USER_NUM2;
</script>
</head>
<body>
<p style="text-align:center; font-size:large">
<script type="text/javascript">
document.write(USER_NUM1 + " + " + USER_NUM2 + " = ");
document.write(NUMS_ADDED + "<br/>");
</script>
</p>
</body>
</html>

Create a new HTML file that prompts the user for his name, the age at which he first worked on a computer, and his
current age. After gathering this information, pop up an alert that tells the user how many years he's been working on a

computer. The images below show the steps:

Notice that the program is able to deal with numbers followed by strings (e.g, "12 years old").

Where is the solution?

User-defined Functions
Writing functions makes it possible to reuse code for common tasks. Functions can also be used to hide complex code.
For example, an experienced developer can write a function for performing a complicated task. Other developers do not
need to know how that function works; they only need to know how to call it.

Function Syntax

JavaScript functions generally appear in the head of the page or in external JavaScript files. A function is written using
the function keyword followed by the name of the function.

Syntax
function doSomething(){
//function statements go here
}

As you can see, the body of the function is contained with in curly brackets ({}). The following example demonstrates
the use of simple functions.

Code Sample: JavaScriptFunctions/Demos/SimpleFunctions.html


<html>
<head>
<title>JavaScript Simple Functions</title>
<script type="text/javascript">
function changeBgRed(){
document.bgColor = "red";
}

function changeBgWhite(){
document.bgColor = "white";
}
</script>
</head>
<body>
<p align="center">
<span onclick="changeBgRed();">Red</span> |
<span onclick="changeBgWhite();">White</span>
</p>
</body>
</html>

Passing Values to Functions

The functions above aren't very useful because they always do the same thing. Every time we wanted to add another
color, we would have to write another function. Also, if we want to modify the behavior, we will have to do it in each
function. The example below shows how to create a single function to handle changing the background color.

Code Sample: JavaScriptFunctions/Demos/PassingValues.html


<html>
<head>
<title>JavaScript Simple Functions</title>
<script type="text/javascript">
function changeBg(color){
document.bgColor = color;
}
</script>
</head>
<body>
<p align="center">
<span onclick="changeBg('red');">Red</span> |
<span onclick="changeBg('white');">White</span>
</p>
</body>
</html>
Code Explanation

As you can see, when calling the changeBG() function, we pass a value (e.g, 'red'), which is assigned to the color
variable. We can then refer to the color variable throughout the function. Variables created in this way are called
function arguments or parameters. A function can have any number of arguments, separated by commas.

A Note on Variable Scope

Variables created through function arguments or declared within a function with var are local to the function, meaning
that they cannot be accessed outside of the function.

Variables declared with var outside of a function and variables that are used without being declared are global, meaning
that they can be used anywhere on the page.

Exercise: Writing a JavaScript Function

Duration: 15 to 25 minutes.

In this exercise, you will modify a page called ColorMania.html, which will contain a form with four buttons. Each
button will show the name of a color (e.g, red) and, when clicked, call a function that changes the background color.
The buttons you will create will be of type button. For example,

<input type="button" value="red" onclick="functionCall();">


1. Open JavaScriptFunctions/Exercises/ColorMania.html for editing.
2. Write code to prompt the user for her name.
3. Write a function called changeBg() that changes the background color and then pops up an alert telling the
user, by name, what the new background color is.
4. In the form, add four buttons that, when clicked, call the changeBg() function and pass it a color value.

The resulting page should look like this:

Code Sample: JavaScriptFunctions/Exercises/ColorMania.html


<html>
<head>
<title>Colormania</title>
<script type="text/javascript">
//PROMPT USER FOR NAME

/*
Write a function called changeBg() that changes the background
color and then pops up an alert telling the user, by name, what
the new background color is.
*/
</script>
</head>
<body>
<form style="text-align:center">
<!--ADD BUTTONS HERE-->
</form>
</body>
</html>

Add another button called "custom" that, when clicked, prompts the user for a color, then changes the background color
to the user-entered color and alerts the user to the change.

Where is the solution?

Returning Values from Functions

The return keyword is used to return values from functions as the following example illustrates.

Code Sample: JavaScriptFunctions/Demos/ReturnValue.html


<html>
<head>
<title>Returning a Value</title>
<script type="text/javascript">
function setBgColor(){
document.bgColor = prompt("Set Background Color:", "");
}

function getBgColor(){
return document.bgColor;
}
</script>
</head>

<body>
<form>
<input type="button" value="Set Background Color"
onclick="setBgColor();">
<input type="button" value="Get Background Color"
onclick="alert(getBgColor());">
</form>
</body>
</html>
Code Explanation
When the user clicks on the "Get Background Color" button, an alert pops up with a value returned from the
getBgColor() function. This is a very simple example. Generally, functions that return values are a bit more involved.
We'll see many more functions that return values throughout the course.

JavaScript Functions Conclusion


In this lesson of the JavaScript tutorial, you have learned to work with JavaScript's built-in functions and to create
functions of your own.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Built-In JavaScript Objects
In this lesson of the JavaScript tutorial, you will learn...

1. To work with the built-in String object.


2. To work with the built-in Math object.
3. To work with the built-in Date object.

JavaScript has some predefined, built-in objects that do not fit into the HTML DOM, meaning that they are not direct
descendants of the window object.

String
In JavaScript, there are two types of string data types: primitive strings and String objects. String objects have many
methods for manipulating and parsing strings of text. Because these methods are available to primitive strings as well,
in practice, there is no need to differentiate between the two types of strings.

Some common string properties and methods are shown below. In all the examples, the variable MY_STRING contains
"Webucator".

Common String Properties


Property Description Example
MY_STRING.length
length Read-only value containing the number of characters in the string. //Returns 9

Common String Methods


Method Description Example
charAt(position)
Returns the character at the specified MY_STRING.charAt(4)
position. //Returns c

charCodeAt(position)
Returns the Unicode character code of MY_STRING.charCodeAt(4)
the character at the specified position. //Returns 99

Returns the text representation of the


fromCharCode(characterCodes)
specifies comma-delimited character String.fromCharCode(169)
codes. Used with String rather than a //Returns ©
specific String object.
Searches from startPosition for substring. MY_STRING.indexOf("cat");
//Returns 4
indexOf(substring, Returns the position at which the
startPosition) substring is found. If substring is not MY_STRING.indexOf("cat", 5);
found, returns -1. //Returns -1

Searches from the end of the string for MY_STRING.lastIndexOf("cat");


substring until endPosition is reached. //Returns 4
lastIndexOf(substring,
endPosition) Returns the position at which the
substring is found. If substring is not MY_STRING.lastIndexOf("cat", 5);
//Returns 4
found, returns -1.
Returns the substring beginning at MY_STRING.substring(4, 7);
startPosition and ending with the //Returns cat
substring(startPosition,
endPosition) character before endPosition. endPosition
is optional. If it is excluded, the substring MY_STRING.substring(4);
//Returns cator
continues to the end of the string.
Returns the substring of Length MY_STRING.substr(4, 3);
characters beginning at startPosition. //Returns cat
substr(startPosition,
length) length is optional. If it is excluded, the
substring continues to the end of the MY_STRING.substr(4);
//Returns cator
string.
Common String Methods
Method Description Example
slice(startPosition, Same as substring(startPosition, MY_STRING.slice(4, 7);
endPosition) endPosition). //Returns cat

positionFromEnd is a negative integer.


Returns the the substring beginning at
slice(startPosition, MY_STRING.slice(4, -2);
positionFromEnd) startPosition and ending //Returns cat
positionFromEnd characters from the end
of the string.
var s = "A,B,C,D";
split(delimiter)
Returns an array by splitting a string on var a = s.split(",");
the specified delimiter. document.write(a[2]);
//Returns C
MY_STRING.toLowerCase()
toLowerCase() Returns the string in all lowercase letters. //Returns webucator
MY_STRING.toUpperCase();
toUpperCase() Returns the string in all uppercase letters. //Returns WEBUCATOR

You can see these examples in a browser by opening BuiltInObjects/Demos/StringPropertiesAndMethods.html.

Math
The Math object is a built-in static object. The Math object's properties and methods are accessed directly (e.g,
Math.PI) and are used for performing complex math operations. Some common math properties and methods are
shown below.

Common Math Properties


Property Description Example
Math.PI;
Math.PI
//3.141592653589793
Pi ( )
Math.SQRT2;
Math.SQRT2 Square root of 2. //1.4142135623730951

Common Math Methods


Method Description Example
Math.abs(-12);
Math.abs(number) Absolute value of number. //Returns 12
Math.ceil(5.4);
Math.ceil(number) number rounded up. //Returns 6
Math.floor(5.6);
Math.floor(number) number rounded down. //Returns 5
Math.max(2, 5, 9, 3);
Math.max(numbers) Highest Number in numbers. //Returns 9
Math.min(2, 5, 9, 3);
Math.min(numbers) Lowest Number in numbers. //Returns 2
Math.pow(2, 5);
Math.pow(number, power) number to the power of power. //Returns 32
Math.round(2.5);
Math.round(number) Rounded number. //Returns 3
Math.random();
Math.random() Random number between 0 and 1. //Returns random
//number from 0 to 1

You can see these examples in a browser by opening BuiltInObjects/Demos/MathPropertiesAndMethods.html.

Method for Generating Random Integers

var LOW = 1;
var HIGH = 10;
var RND1 = Math.random();
var RND2 = Math.round(RND1 * (HIGH - LOW) + 1);

Date
The Date object has methods for manipulating dates and times. JavaScript stores dates as the number of milliseconds
since January 1, 1970. The sample below shows the different methods of creating date objects, all of which involve
passing arguments to the Date() constructor.

Code Sample: BuiltInObjects/Demos/DateObject.html


<html>
<head>
<title>Date Object</title>
</head>
<body>
<h1>Date Object</h1>
<h2>New Date object with current date and time</h2>
<pre>
//Syntax: new Date();
var NOW = new Date();
</pre>
<b>Result:</b>
<script type="text/javascript">
var NOW = new Date();
document.write(NOW);
</script>

<h2>New Date object with specific date and time</h2>


<pre>
//Syntax: new Date("month dd, yyyy hh:mm:ss);
var RED_SOX_WINS = new Date("October 21, 2004 12:01:00");
</pre>
<b>Result:</b>
<script type="text/javascript">
var RED_SOX_WINS = new Date("October 21, 2004 12:01:00");
document.write(RED_SOX_WINS);
</script>

<pre>
//Syntax: new Date(yyyy, mm, dd, hh, mm, ss, ms);
RED_SOX_WINS = new Date(2004, 9, 21, 12, 01, 00, 00);
</pre>
<b>Result:</b>
<script type="text/javascript">
RED_SOX_WINS = new Date(2004, 9, 21, 12, 01, 00, 00);
document.write(RED_SOX_WINS);
</script>
</body>
</html>
Code Explanation

This page is shown in a browser below.

A few things to note:

• To create a Date object containing the current date and time, the Date() constructor takes no arguments.
• When passing the date as a string to the Date() constructor, the time portion is optional. If it is not included, it
defaults to 00:00:00. Also, other date formats are acceptable (e.g, "10/21/2004" and "10-04-2004").
• When passing date parts to the Date() constructor, dd, hh, mm, ss, and ms are all optional. The default of each
is 0.
• Months are numbered from 0 (January) to 11 (December). In the example above, 9 represents October.

Some common date methods are shown below. In all the examples, the variable RIGHT_NOW contains "Thu Apr 14
00:23:54:650 EDT 2005".
Common Date Methods
Method Description Example
RIGHT_NOW.getDate();
getDate() Returns the day of the month (1-31). //Returns 14

getDay()
Returns the day of the week as a number (0-6, RIGHT_NOW.getDay();
0=Sunday, 6=Saturday). //Returns 4

getMonth()
Returns the month as a number (0-11, 0=January, RIGHT_NOW.getMonth();
11=December). //Returns 3
RIGHT_NOW.getFullYear();
getFullYear() Returns the four-digit year. //Returns 2005
RIGHT_NOW.getHours();
getHours() Returns the hour (0-23). //Returns 0
RIGHT_NOW.getMinutes();
getMinutes() Returns the minute (0-59). //Returns 23
RIGHT_NOW.getSeconds();
getSeconds() Returns the second (0-59). //Returns 54
RIGHT_NOW.getMilliseconds();
getMilliseconds() Returns the millisecond (0-999). //Returns 650

getTime()
Returns the number of milliseconds since midnight RIGHT_NOW.getTime();
January 1, 1970. //Returns 1113452634650

getTimezoneOffset()
Returns the time difference in minutes between the RIGHT_NOW.getTimezoneOffset();
user's computer and GMT. //Returns 240
RIGHT_NOW.toLocaleString();
toLocaleString() Returns the Date object as a string. //Returns Thursday, April 14,
//2005 12:23:54 AM
RIGHT_NOW.toGMTString();
toGMTString()
Returns the Date object as a string in GMT //Returns Thu, 14 Apr 2005
timezone. //04:23:54 UTC

You can see these examples in a browser by opening BuiltInObjects/Demos/DateMethods.html.

typeof Operator
The typeof operator is used to find out the type of a piece of data. The screenshot below shows what the typeof operator
returns for different data types.

Some languages have functions that return the the month as a string. JavaScript doesn't have such a built-in function.
The sample below shows a user-defined function that handles this and how the getMonth() method of a Date object can
be used to get the month.

Code Sample: BuiltInObjects/Demos/MonthAsString.html


<html>
<head>
<title>Month As String</title>
<script type="text/javascript">
function monthAsString(num){
var months = [];
months[0] = "January";
months[1] = "February";
months[2] = "March";
months[3] = "April";
months[4] = "May";
months[5] = "June";
months[6] = "July";
months[7] = "August";
months[8] = "September";
months[9] = "October";
months[10] = "November";
months[11] = "December";

return months[num-1];
}

function enterMonth(){
var userMonth = prompt("What month were you born?", "");
alert("You were born in " + monthAsString(userMonth) + ".");
}

function getCurrentMonth(){
var today = new Date();
alert(monthAsString(today.getMonth()+1));
}
</script>
</head>
<body>
<form>
<input type="button" value="CHOOSE MONTH" onclick="enterMonth();">
<input type="button" value="GET CURRENT MONTH" onclick="getCurrentMonth();">
</form>
</body>
</html>

Exercise: Returning the Day of the Week as a String

Duration: 15 to 25 minutes.

In this exercise, you will create a function that returns the day of the week as a string.

1. Open BuiltInObjects/Exercises/DateUDFs.html for editing.


2. Write a dayAsString() function that returns the day of the week as a string.
3. Write an enterDay() function that prompts the user for the day of the week and then alerts the string value of
that day by calling the dayAsString() function.
4. Write a getCurrentDay() function that alerts today's actual day of the week according to the user's machine.
5. Add a "CHOOSE DAY" button that calls the enterDay() function.
6. Add a "GET CURRENT DAY" button that calls the getCurrentDay() function.
7. Test your solution in a browser.

Where is the solution?

Built-In JavaScript Objects Conclusion


In this lesson of the JavaScript tutorial, you have learned to work with some of JavaScript's most useful built-in objects.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Conditionals and Loops
In this lesson of the JavaScript tutorial, you will learn...

1. To write if - else if - else blocks.


2. To write switch / case blocks.
3. To return values from functions.
4. To work with loops in JavaScript.

Conditionals
There are two types of conditionals in JavaScript.

1. if - else if - else
2. switch / case

if - else if - else Conditions

Syntax
if (conditions) {
statements;
} else if (conditions) {
statements;
} else {
statements;
}

Like with functions, each part of the if - else if - else block is contained within curly brackets ({}). There can be zero or
more else if blocks. The else block is optional.

Comparison Operators
Operator Description
== Equals
!= Doesn't equal
=== Strictly equals
!== Doesn't strictly equal
> Is greater than
< Is less than
>= Is greater than or equal to
<= Is less than or equal to
Logical Operators
Operator Description
&& and (a == b && c != d)
|| or (a == b || c != d)
! not !(a == b || c != d)

The example below shows a function using and if - else if - else condition.

Code Sample: ConditionalsAndLoops/Demos/IfElseifElse.html


<html>
<head>
<title>JavaScript Conditionals Demo</title>
<script type="text/javascript">
function checkAge(){
var age = prompt("Your age?", "") || "";

if (age >= 21) {


alert("You can vote and drink!");
} else if (age >= 18) {
alert("You can vote, but can't drink.");
} else {
alert("You cannot vote or drink.");
}
}
</script>
</head>
<body style="text-align:center">
<h1>JavaScript if - else if - else Demo</h1>
<h3>Age Check</h3>
<form>
<input type="button" value="Age Check" onclick="checkAge();">
</form>
</body>
</html>
Code Explanation

The display of the page is shown below.

When the user clicks on the Age Check button, the following prompt pops up.

After the user enters his age, an alert pops up. The text of the alert depends on the user's age. The three possibilities are

shown below.

Compound Conditions

Compound conditions are conditions that check for multiple things. See the sample below.

if (age > 18 && isCitizen) {


alert("You can vote!");
}

if (age >= 16 && (isCitizen || hasGreenCard)) {


alert("You can work in the United States");
}

Short-circuiting

JavaScript is lazy (or efficient) about processing compound conditions. As soon as it can determine the overall result of
the compound condition, it stops looking at the remaining parts of the condition. This is useful for checking that a
variable is of the right data type before you try to manipulate it.

To illustrate, take a look at the following sample.

Code Sample: ConditionalsAndLoops/Demos/PasswordCheckBroken.html


<html>
<head>
<title>Password Check</title>
<script type="text/javascript">
var USER_PASS = prompt("Password:", ""); //ESC here causes problems
var PASSWORD = "xyz";
</script>
</head>

<body>
<script type="text/javascript">
if (USER_PASS.toLowerCase() == PASSWORD) {
document.write("<h1>Welcome!</h1>");
} else {
document.write("<h1>Bad Password!</h1>");
}
</script>
</body>
</html>
Code Explanation

Everything works fine as long as the user does what you expect. However, if the user clicks on the Cancel button when
prompted for a password, the value null will be assigned to USER_PASS. Because null is not a string, it does not have
the toLowerCase() method. So the following line will result in a JavaScript error.

if (USER_PASS.toLowerCase() == password)

This can be fixed by using the typeof() function to first check if USER_PASS is a string as shown in the sample below.

Code Sample: ConditionalsAndLoops/Demos/PasswordCheck.html


<html>
<head>
<title>Password Check</title>
<script type="text/javascript">
var USER_PASS = prompt("Password:", "") || "";
var PASSWORD = "xyz";
</script>
</head>

<body>
<script type="text/javascript">
if (typeof USER_PASS == "string" && USER_PASS.toLowerCase() == PASSWORD) {
document.write("<h1>Welcome!</h1>");
} else {
document.write("<h1>Bad Password!</h1>");
}
</script>
</body>
</html>

Switch / Case

Syntax
switch (expression) {
case value :
statements;
case value :
statements;
default :
statements;
}

Like if - else if - else statements, switch/case statements are used to run different code at different times. Generally,
switch/case statements run faster than if - else if - else statements, but they are limited to checking for equality. Each
case is checked to see if the expression matches the value.

Take a look at the following example.

Code Sample: ConditionalsAndLoops/Demos/SwitchWithoutBreak.html


<html>
<head>
<title>Switch</title>
<script type="text/javascript">
var QUANTITY = 1;
switch (QUANTITY) {
case 1 :
alert("QUANTITY is 1");
case 2 :
alert("QUANTITY is 2");
default :
alert("QUANTITY is not 1 or 2");
}
</script>
</head>
<body>
Nothing to show here.
</body>
</html>
Code Explanation

When you run this page in a browser, you'll see that all three alerts pop up, even though only the first case is a match.
That's because if a match is found, none of the remaining cases is checked and all the remaining statements in the
switch block are executed. To stop this process, you can insert a break statement, which will end the processing of the
switch statement.

The corrected code is shown in the example below.

Code Sample: ConditionalsAndLoops/Demos/SwitchWithBreak.html


<html>
<head>
<title>Switch</title>
<script type="text/javascript">
var QUANTITY = 1;
switch (QUANTITY) {
case 1 :
alert("QUANTITY is 1");
break;
case 2 :
alert("QUANTITY is 2");
break;
default :
alert("QUANTITY is not 1 or 2");
}
</script>
</head>
<body>
Nothing to show here.
</body>
</html>

The following example shows how a switch/case statement can be used to record the user's browser type.

Code Sample: ConditionalsAndLoops/Demos/BrowserSniffer.html


<html>
<head>
<title>Simple Browser Sniffer</title>
<script type="text/javascript">
switch (navigator.appName) {
case "Microsoft Internet Explorer" :
alert("This is IE!");
break;
case "Netscape" :
alert("This is Mozilla!");
break;
default :
alert("This is something other than IE or Mozilla!");
}
</script>
</head>
<body>
Nothing to show here.
</body>
</html>
Code Explanation

The navigator object, which is a child of window, holds information about the user's browser. In this case we are
looking at the appName property, which has a value of "Microsoft Internet Explorer" for Internet Explorer and
"Netscape" for Mozilla-based browsers (e.g, Navigator, Firefox).

Exercise: Conditional Processing

Duration: 20 to 30 minutes.

In this exercise, you will practice using conditional processing.

1. Open ConditionalsAndLoops/Exercises/Conditionals.html for editing.


2. Notice that there is an onload event handler that calls the greetUser() function. Create this function in the
script block.
3. The function should do the following:
1. Prompt the user for his/her gender and last name and store the results in variables.
2. If the user enters a gender other than "Male" or "Female", prompt him/her to try again.
3. If the user leaves the last name blank, prompt him/her to try again.
4. If the user enters a number for the last name, tell him/her that a last name can't be a number and
prompt him/her to try again.
5. After collecting the gender and last name:
ƒ If the gender is valid, pop up an alert that greets the user appropriately (e.g, "Hello Ms.
Smith!")
ƒ If the gender is not valid, pop up an alert that reads something like "XYZ is not a
gender!"
4. Test your solution in a browser.

1. Allow the user to enter his/her gender in any case.


2. If the user enters a last name that does not start with a capital letter, prompt him/her to try again.

Where is the solution?

Loops
There are several types of loops in JavaScript.

• while
• do...while
• for
• for...in

while Loop Syntax

Syntax
while (conditions) {
statements;
}

Something, usually a statement within the while block, must cause the condition to change so that it eventually
becomes false and causes the loop to end. Otherwise, you get stuck in an infinite loop, which can bring down the
browser.

do...while Loop Syntax


Syntax
do {
statements;
} while (conditions);

Again something, usually a statement within the do block, must cause the condition to change so that it eventually
becomes false and causes the loop to end.

Unlike with while loops, the statements in do...while loops will always execute at least one time because the conditions
are not checked until the end of each iteration.

for Loop Syntax

Syntax
for (initialization; conditions; change) {
statements;
}

In for loops, the initialization, conditions, and change are all placed up front and separated by semi-colons. This makes
it easy to remember to include a change statement that will eventually cause the loop to end.

for loops are often used to iterate through arrays. The length property of an array can be used to check how many
elements the array contains.

for...in Loop Syntax

Syntax
for (var item in array) {
statements;
}

for...in loops are specifically designed for looping through arrays. For reasons that will be better understood when we
look at object augmentation, the above syntax has a slight flaw. If the Array class is changed, it is possible that the
for...in loop includes more items than what you anticipated.

To be on the safe side, we suggest that you use a more verbose syntax as seen below.

Syntax
for (var item in array) if (array.hasOwnProperty(item)) {
statements;
}

The hasOwnProperty() call will ensure that the item is indeed an element that you added to the array, not something
that was inherited because of object augmentation.

Code Sample: ConditionalsAndLoops/Demos/Loops.html


<html>
<head>
<title>JavaScript Loops</title>
<script type="text/javascript">
var INDEX;
var BEATLES = [];
BEATLES["Guitar1"] = "John";
BEATLES["Bass"] = "Paul";
BEATLES["Guitar2"] = "George";
BEATLES["Drums"] = "Ringo";
var RAMONES = ["Joey", "Johnny", "Dee Dee", "Mark"];
</script>
</head>

<body>
<h1>JavaScript Loops</h1>
<h2>while Loop</h2>
<script type="text/javascript">
INDEX = 0;
while (INDEX < 5) {
document.write(INDEX);
INDEX++;
}
</script>

<h2>do...while Loop</h2>
<script type="text/javascript">
INDEX = 1;
do {
document.write(INDEX);
INDEX++;
} while (INDEX < 5);
</script>

<h2>for Loop</h2>
<script type="text/javascript">
for (var INDEX=0; INDEX<=5; INDEX++) {
document.write(INDEX);
}
</script>

<h2>for Loop with Arrays</h2>


<ol>
<script type="text/javascript">
for (var INDEX=0; INDEX<RAMONES.length; INDEX++) {
document.write("<li>" + RAMONES[INDEX] + "</li>");
}
</script>
</ol>

<h2>for...in Loop</h2>
<ol>
<script type="text/javascript">
for (var instrument in BEATLES) if (BEATLES.hasOwnProperty(instrument)) {
document.write("<li>Playing " + instrument + " there is " + BEATLES[instrument] + "</li>");
}
</script>
</ol>
</body>
</html>
Code Explanation

The sample above shows demos of all the aforementioned loops.

Exercise: Working with Loops

Duration: 20 to 30 minutes.

In this exercise, you will practice working with loops.

1. Open ConditionalsAndLoops/Exercises/Loops.html for editing. You will see that this file is similar to the
solution from the last exercise.
2. Declare an additional variable called greeting.
3. Create an array called presidents that contains the last names of four or more past presidents.
4. Currently, the user only gets two tries to enter a valid gender and lastName. Modify the code so that, in both
cases, the user continues to get prompted until he enters valid data.
5. Change the switch block so that it assigns an appropriate value (e.g, "Hello Ms. Smith") to the greeting
variable rather than popping up an alert.
6. After the switch block, write code that alerts the user by name if he has the same last name as a president.
There is no need to alert those people who have non-presidential names.

1. Modify the code so that the first prompt for gender reads "What gender are you: Male or Female?", but all
subsequent prompts for gender read "You must enter 'Male' or 'Female'. Try again:".
2. Modify the code so that the first prompt for last name reads "Enter your last name:", but all subsequent
prompts for last name read "Please enter a valid last name:".
3. If the user presses the Cancel button on a prompt dialog, it returns null. Test this. It very likely results in a
JavaScript error. If so, fix the code so that no JavaScript error occurs.
4. For those people who do not have presidential names, pop up an alert that tells them their names are not
presidential.

Where is the solution?

Conditionals and Loops Conclusion


In this lesson of the JavaScript tutorial, you learned to work with JavaScript if-else if-else and switch/case conditionals
and several types of loops.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
JavaScript Form Validation
In this lesson of the JavaScript tutorial, you will learn...

1. To access data entered by users in forms.


2. To validate text fields and passwords.
3. To validate radio buttons.
4. To validate checkboxes.
5. To validate select menus.
6. To validate textareas.
7. To write clean, reusable validation functions.
8. To catch focus, blur, and change events.

Accessing Form Data


All forms on a web page are stored in the document.forms[] array. The first form on a page is document.forms[0], the
second form is document.forms[1], and so on. However, it is usually easier to give the forms names (with the name
attribute) and refer to them that way. For example, a form named LoginForm can be referenced as
document.LoginForm. The major advantage of naming forms is that the forms can be repositioned on the page without
affecting the JavaScript.

Elements within a form are properties of that form and are referenced as follows:

Syntax
document.FormName.ElementName

Text fields and passwords have a value property that holds the text value of the field. The following example shows
how JavaScript can access user-entered text.

Code Sample: FormValidation/Demos/FormFields.html


<html>
<head>
<title>Form Fields</title>
<script type="text/javascript">
function changeBg(){
var userName = document.forms[0].UserName.value;
var bgColor = document.BgForm.BgColor.value;

document.bgColor = bgColor;
alert(userName + ", the background color is " + bgColor + ".");
}
</script>
</head>
<body>
<h1>Change Background Color</h1>
<form name="BgForm">

Your Name: <input type="text" name="UserName" size="10"><br/>


Background Color: <input type="text" name="BgColor" size="10"><br/>

<input type="button" value="Change Background" onclick="changeBg();">


</form>
</body>
</html>
Code Explanation

Some things to notice:

1. When the user clicks on the "Change Background" button, the changeBg() function is called.
2. The values entered into the UserName and BgColor fields are stored in variables (userName and bgColor).
3. This form can be referenced as forms[0] or BgForm. The UserName field is referenced as
document.forms[0].UserName.value and the BgColor field is referenced as
document.BgForm.BgColor.value.

Exercise: Textfield to Textfield

Duration: 15 to 25 minutes.

In this exercise, you will write a function that bases the value of one text field on the value of another.

1. Open FormValidation/Exercises/TextfieldToTextField.html for editing.


2. Write a function called getMonth() that passes the month number entered by the user to the monthAsString()
function in DateUDFs.js and writes the result in the MonthName field.

Code Sample: FormValidation/Exercises/TextfieldToTextField.html


<html>
<head>
<title>Textfield to Textfield</title>
<script src="DateUDFs.js" type="text/javascript"></script>
<script type="text/javascript">
/*
Write a function called getMonth() that passes the
month number entered by the user to the monthAsString()
function in DateUDFs.js and writes the result in
the MonthName field.
*/
</script>
</head>
<body>
<h1>Month Check</h1>
<form name="DateForm">
Month Number: <input type="text" name="MonthNumber" size="2">
<input type="button" value="Get Month" onclick="getMonth();"><br>
Month Name: <input type="text" name="MonthName" size="10">
</form>
</body>
</html>

1. If the user enters a number less than 1 or greater than 12 or a non-number, have the function write "Bad
Number" in the MonthName field.
2. If the user enters a decimal between 1 and 12 (inclusive), strip the decimal portion of the number.

Where is the solution?

Basics of Form Validation


When the user clicks on a submit button, an event occurs that can be caught with the form tag's onsubmit event handler.
Unless JavaScript is used to explicitly cancel the submit event, the form will be submitted. The return false; statement
explicitly cancels the submit event. For example, the following form will never be submitted.

<form action="Process.html" onsubmit="return false;">


<!--Code for form fields would go here-->
<input type="submit" value="Submit Form">
</form>

Of course, when validating a form, we only want the form not to submit if something is wrong. The trick is to return
false if there is an error, but otherwise return true. So instead of returning false, we call a validation function, which
will specify the result to return.

<form action="Process.html" onsubmit="return validate(this);">


The this Object

Notice that we pass the validate() function the this object. The this object refers to the current object - whatever object
(or element) the this keyword appears in. In the case above, the this object refers to the form object. So the entire form
object is passed to the validate() function. Let's take a look at a simple example.

Code Sample: FormValidation/Demos/Login.html


<html>
<head>
<title>Login</title>
<script type="text/javascript">
function validate(form){
var userName = form.Username.value;
var password = form.Password.value;

if (userName.length === 0) {
alert("You must enter a username.");
return false;
}

if (password.length === 0) {
alert("You must enter a password.");
return false;
}

return true;
}
</script>
</head>
<body>
<h1>Login Form</h1>
<form method="post" action="Process.html"
onsubmit="return validate(this);">

Username: <input type="text" name="Username" size="10"><br/>


Password: <input type="password" name="Password" size="10"><br/>

<input type="submit" value="Submit">


<input type="reset" value="Reset Form">
</p>
</form>
</body>
</html>
Code Explanation

1. When the user submits the form, the onsubmit event handler captures the event and calls the validate()
function, passing in the form object.
2. The validate() function stores the form object in the form variable.
3. The values entered into the Username and Password fields are stored in variables (userName and password).
4. An if condition is used to check if userName is an empty string. If it is, an alert pops up explaining the
problem and the function returns false. The function stops processing and the form does not submit.
5. An if condition is used to check that password is an empty string. If it is, an alert pops up explaining the
problem and the function returns false. The function stops processing and the form does not submit.
6. If neither if condition catches a problem, the function returns true and the form submits.

Cleaner Validation

There are a few improvements we can make on the last example.

One problem is that the validation() function only checks for one problem at a time. That is, if it finds and error, it
reports it immediately and does not check for additional errors. Why not just tell the user all the mistakes that need to
be corrected, so he doesn't have to keep submitting the form to find each subsequent error?

Another problem is that the code is not written in a way that makes it easily reusable. For example, checking for the
length of user-entered values is a common thing to do, so it would be nice to have a ready-made function to handle this.
These improvements are made in the example below.

Code Sample: FormValidation/Demos/Login2.html


<html>
<head>
<title>Login</title>
<script type="text/javascript">
function validate(form){
var userName = form.Username.value;
var password = form.Password.value;
var errors = [];

if (!checkLength(userName)) {
errors[errors.length] = "You must enter a username.";
}

if (!checkLength(password)) {
errors[errors.length] = "You must enter a password.";
}

if (errors.length > 0) {
reportErrors(errors);
return false;
}

return true;
}

function checkLength(text, min, max){


min = min || 1;
max = max || 10000;

if (text.length < min || text.length > max) {


return false;
}
return true;
}

function reportErrors(errors){
var msg = "There were some problems...\n";
var numError;
for (var i = 0; i<errors.length; i++) {
numError = i + 1;
msg += "\n" + numError + ". " + errors[i];
}
alert(msg);
}
</script>
</head>
<body>
<h1>Login Form</h1>
<form method="post" action="Process.html"
onsubmit="return validate(this);">

Username: <input type="text" name="Username" size="10"><br/>


Password: <input type="password" name="Password" size="10"><br/>

<input type="submit" value="Submit">


<input type="reset" value="Reset Form">
</p>
</form>
</body>
</html>
Code Explanation

Some things to notice:

1. Two additional functions are created: checkLength() and reportErrors().


o The checkLength() function takes three arguments, the text to examine, the required minimum
length, and the required maximum length. If the minimum length and maximum length are not
passed, defaults of 1 and 10000 are used.
o The reportErrors() function takes one argument, an array holding the errors. It loops through the
errors array creating an error message and then it pops up an alert with this message. The \n is an
escape character for a newline.
2. In the main validate() function, a new array, errors, is created to hold any errors that are found.
3. userName and password are passed to checkLength() for validation.
o If errors are found, they are appended to errors.
4. If there are any errors in errors (i.e, if its length is greater than zero), then errors is passed to reportErrors(),
which pops up an alert letting the user know where the errors are. The validate() function then returns false
and the form is not submitted.
5. If no errors are found, the validate() function returns true and the form is submitted.

By modularizing the code in this way, it makes it easy to add new validation functions. In the next examples we will
move the reusable validation functions into a separate JavaScript file called FormValidation.js.

Exercise: Validating a Registration Form

Duration: 25 to 40 minutes.

In this exercise, you will write code to validate a registration form.

1. Open FormValidation/Exercises/FormValidation.js for editing.


o Create a function called compareValues() that takes two arguments: val1 and val2. The function
should return:
ƒ 0 if the two values are equal
ƒ -1 if val1 is greater than val2
ƒ 1 if val2 is greater than val1
o Create a function called checkEmail() that takes one argument: email. The function should return:
ƒ false if email has fewer than 6 characters
ƒ false if email does not contain an @ symbol
ƒ false if email does not contain a period (.)
ƒ true otherwise
2. Open FormValidation/Exercises/Register.html for editing.
o Add code so that the functions in FormValidation.js are accessible from this page.
o Create a validate() function that does the following:
ƒ Checks that the FirstName, LastName, City, Country, UserName, and Password1 fields
are filled out.
ƒ Checks that the middle initial is a single character.
ƒ Checks that the state is exactly two characters.
ƒ Checks that the email is a valid email address.
ƒ Checks that the values entered into Password1 and Password2 are the same.
ƒ If there are errors, passes reportErrors() the errors array and returns false.
ƒ If there are no errors, returns true.
3. Test your solution in a browser.

In FormValidation/Exercises/FormValidation.js, modify the checkEmail() function so that it also checks to see that the
final period (.) is after the final @ symbol. The solution is included in FormValidation/Solutions/FormValidation.js.

Where is the solution?

Validating Radio Buttons


Radio buttons that have the same name are grouped as arrays. Generally, the goal in validating a radio button array is to
make sure that the user has checked one of the options. Individual radio buttons have the checked property, which is
true if the button is checked and false if it is not. The example below shows a simple function for checking radio button
arrays.
Code Sample: FormValidation/Demos/RadioArrays.html
<html>
<head>
<title>Radio Arrays</title>
<script type="text/javascript">
function validate(form){
var errors = [];

if ( !checkRadioArray(form.container) ) {
errors[errors.length] = "You must choose a cup or cone.";
}

if (errors.length > 0) {
reportErrors(errors);
return false;
}

return true;
}

function checkRadioArray(radioButtons){
for (var i=0; i < radioButtons.length; i++) {
if (radioButtons[i].checked) {
return true;
}
}
return false;
}

function reportErrors(errors){
var msg = "There were some problems...\n";
var numError;
for (var i = 0; i<errors.length; i++) {
numError = i + 1;
msg += "\n" + numError + ". " + errors[i];
}
alert(msg);
}
</script>
</head>
<body>
<h1>Ice Cream Form</h1>
<form method="post" action="Process.html"
onsubmit="return validate(this);">
<b>Cup or Cone?</b>
<input type="radio" name="container" value="cup"> Cup
<input type="radio" name="container" value="plaincone"> Plain cone
<input type="radio" name="container" value="sugarcone"> Sugar cone
<input type="radio" name="container" value="wafflecone"> Waffle cone
<br/><br/>
<input type="submit" value="Place Order">
</form>

</body>
</html>
Code Explanation

The checkRadioArray() function takes a radio button array as an argument, loops through each radio button in the
array, and returns true as soon as it finds one that is checked. Since it is only possible for one option to be checked,
there is no reason to continue looking once a checked button has been found. If none of the buttons is checked, the
function returns false.

Validating Checkboxes
Like radio buttons, checkboxes have the checked property, which is true if the button is checked and false if it is not.
However, unlike radio buttons, checkboxes are not stored as arrays. The example below shows a simple function for
checking to make sure a checkbox is checked.

Code Sample: FormValidation/Demos/CheckBoxes.html


<html>
<head>
<title>Checkboxes</title>
<script type="text/javascript">
function validate(form){
var errors = [];

if ( !checkCheckBox(form.terms) ) {
errors[errors.length] = "You must agree to the terms.";
}

if (errors.length > 0) {
reportErrors(errors);
return false;
}

return true;
}

function checkCheckBox(cb){
return cb.checked;
}

function reportErrors(errors){
var msg = "There were some problems...\n";
var numError;
for (var i = 0; i<errors.length; i++) {
numError = i + 1;
msg += "\n" + numError + ". " + errors[i];
}
alert(msg);
}
</script>
</head>
<body>
<h1>Ice Cream Form</h1>
<form method="post" action="Process.html" onsubmit="return validate(this);">
<input type="checkbox" name="terms">
I understand that I'm really not going to get any ice cream.
<br/><br/>
<input type="submit" value="Place Order">
</form>

</body>
</html>

Validating Select Menus


Select menus contain an array of options. The selectedIndex property of a select menu contains the index of the option
that is selected. Often the first option of a select menu is something meaningless like "Please choose an option..." The
checkSelect() function in the example below makes sure that the first option is not selected.

Code Sample: FormValidation/Demos/SelectMenus.html


<html>
<head>
<title>Check Boxes</title>
<script type="text/javascript">
function validate(form){
var errors = [];

if ( !checkSelect(form.flavor) ) {
errors[errors.length] = "You must choose a flavor.";
}

if (errors.length > 0) {
reportErrors(errors);
return false;
}

return true;
}

function checkSelect(select){
return (select.selectedIndex > 0);
}

function reportErrors(errors){
var msg = "There were some problems...\n";
var numError;
for (var i = 0; i<errors.length; i++) {
numError = i + 1;
msg += "\n" + numError + ". " + errors[i];
}
alert(msg);
}
</script>
</head>
<body>
<h1>Ice Cream Form</h1>
<form method="post" action="Process.html"
onsubmit="return validate(this);">
<b>Flavor:</b>
<select name="flavor">
<option value="0" selected></option>
<option value="choc">Chocolate</option>
<option value="straw">Strawberry</option>
<option value="van">Vanilla</option>
</select>
<br/><br/>
<input type="submit" value="Place Order">
</form>

</body>
</html>

Focus, Blur, and Change Events


Focus, blur and change events can be used to improve the user experience.

Focus and Blur

Focus and blur events are caught with the onfocus and onblur event handlers. These events have corresponding focus()
and blur() methods. The example below shows

1. how to set focus on a field.


2. how to capture when a user leaves a field.
3. how to prevent focus on a field.

Code Sample: FormValidation/Demos/FocusAndBlur.html


<html>
<head>
<title>Focus and Blur</title>
<script src="DateUDFs.js" type="text/javascript"></script>
<script type="text/javascript">
function getMonth(){
var elemMonthNumber = document.DateForm.MonthNumber;
var monthNumber = elemMonthNumber.value;

var elemMonthName = document.DateForm.MonthName;


var month = monthAsString(elemMonthNumber.value);

elemMonthName.value = (monthNumber > 0 && monthNumber <=12) ? month : "Bad Number";


}
</script>
</head>
<body onload="document.DateForm.MonthNumber.focus();">
<h1>Month Check</h1>
<form name="DateForm">
Month Number:
<input type="text" name="MonthNumber" size="2" onblur="getMonth();">
Month Name:
<input type="text" name="MonthName" size="10" onfocus="this.blur();">
</form>
</body>
</html>
Code Explanation

Things to notice:

1. When the document is loaded, the focus() method of the text field element is used to set focus on the
MonthNumber element.
2. When focus leaves the MonthNumber field, the onblur event handler captures the event and calls the
getMonth() function.
3. The onfocus event handler of the MonthName element triggers a call to the blur() method of this (the
MonthName element itself) to prevent the user from focusing on the MonthName element.

Change

Change events are caught when the value of a text element changes or when the selected index of a select element
changes. The example below shows how to capture a change event.

Code Sample: FormValidation/Demos/Change.html


<html>
<head>
<title>Change</title>
<script src="DateUDFs.js" type="text/javascript"></script>
<script type="text/javascript">
function getMonth(){
var elemMonthNumber = document.DateForm.MonthNumber;
var i = elemMonthNumber.selectedIndex;
var monthNumber = elemMonthNumber[i].value;

var elemMonthName = document.DateForm.MonthName;


var month = monthAsString(monthNumber);

elemMonthName.value = (i === 0) ? "" : month;


}
</script>
</head>
<body onload="document.DateForm.MonthNumber.focus();">
<h1>Month Check</h1>
<form name="DateForm">
Month Number:
<select name="MonthNumber" onchange="getMonth();">
<option>--Choose--</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select><br>
Month Name: <input type="text" name="MonthName" size="10"
onfocus="this.blur();">
</form>
</body>
</html>
Code Explanation

This is similar to the last example. The only major difference is that MonthNumber is a select menu instead of a text
field and that the getMonth() function is called when a different option is selected.

Validating Textareas
Textareas can be validated the same way that text fields are by using the checkLength() function shown earlier.
However, because textareas generally allow for many more characters, it's often difficult for the user to know if he's
exceeded the limit. It could be helpful to let the user know if there's a problem as soon as focus leaves the textarea. The
example below, which contains a more complete form for ordering ice cream, includes a function that alerts the user if
there are too many characters in a textarea.

Code Sample: FormValidation/Demos/IceCreamForm.html


<html>
<head>
<title>Check Boxes</title>
<script type="text/javascript">
function validate(form){
var errors = [];

if ( !checkRadioArray(form.container) ) {
errors[errors.length] = "You must choose a cup or cone.";
}

if ( !checkCheckBox(form.terms) ) {
errors[errors.length] = "You must agree to the terms.";
}

if ( !checkSelect(form.flavor) ) {
errors[errors.length] = "You must choose a flavor.";
}

if (errors.length > 0) {
reportErrors(errors);
return false;
}

return true;
}

function checkRadioArray(radioButtons){
for (var i=0; i < radioButtons.length; i++) {
if (radioButtons[i].checked) {
return true;
}
}
return false;
}

function checkCheckBox(cb){
return cb.checked;
}

function checkSelect(select){
return (select.selectedIndex > 0);
}

function checkLength(text, min, max){


min = min || 1;
max = max || 10000;
if (text.length < min || text.length > max) {
return false;
}
return true;
}

function checkTextArea(textArea, max){


var numChars, chopped, message;
if (!checkLength(textArea.value, 0, max)) {
numChars = textArea.value.length;
chopped = textArea.value.substr(0, max);
message = 'You typed ' + numChars + ' characters.\n';
message += 'The limit is ' + max + '.';
message += 'Your entry will be shortened to:\n\n' + chopped;
alert(message);
textArea.value = chopped;
}
}

function reportErrors(errors){
var msg = "There were some problems...\n";
var numError;
for (var i = 0; i<errors.length; i++) {
numError = i + 1;
msg += "\n" + numError + ". " + errors[i];
}
alert(msg);
}
</script>
</head>
<body>
<h1>Ice Cream Form</h1>
<form method="post" action="Process.html" onsubmit="return validate(this);">
<p><b>Cup or Cone?</b>
<input type="radio" name="container" value="cup"> Cup
<input type="radio" name="container" value="plaincone"> Plain cone
<input type="radio" name="container" value="sugarcone"> Sugar cone
<input type="radio" name="container" value="wafflecone"> Waffle cone
</p>
<p>
<b>Flavor:</b>
<select name="flavor">
<option value="0" selected></option>
<option value="choc">Chocolate</option>
<option value="straw">Strawberry</option>
<option value="van">Vanilla</option>
</select>
</p>
<p>
<b>Special Requests:</b><br>
<textarea name="requests" cols="40" rows="6" wrap="virtual"
onblur="checkTextArea(this, 100);"></textarea>
</p>
<p>
<input type="checkbox" name="terms">
I understand that I'm really not going to get any ice cream.
</p>
<input type="submit" value="Place Order">
</form>

</body>
</html>

Exercise: Improving the Registration Form

Duration: 15 to 25 minutes.

In this exercise, you will make some improvements to the registration form from the last exercise.

1. Open FormValidation/Exercises/FormValidation2.js in your editor. You will see that the functions discussed
above have been added: checkRadioArray(), checkCheckBox(), checkSelect(), and checkTextArea().
2. Open FormValidation/Exercises/Register2.html for editing.
o Notice that the following changes have been made to the form:
ƒ State has been changed from a textfield to a select menu. The first option is meaningless.
The next 51 options are U.S. states. The rest of the options are Canadian provinces.
ƒ Country has been changed to a radio array.
ƒ A Comments field has been added.
ƒ A Terms checkbox has been added.
o Write code that:
ƒ Checks that a country is selected.
ƒ Checks that the country and state selection are in sync.
ƒ Checks that the terms have been accepted.
o Add an event handler to the Comments textarea that alerts the user if the comment is too long.
3. Test your solution in a browser.

Where is the solution?

JavaScript Form Validation Conclusion


In this lesson of the JavaScript tutorial, you have learned to capture form events, to reference form fields, and to write
clean, reusable form validation scripts.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Working with Images
In this lesson of the JavaScript tutorial, you will learn...

1. To create image rollovers.


2. To create backward-compatible image rollovers.
3. To preload images.
4. To create a slide show.

Image Rollovers
Image rollovers are commonly used to create a more interesting user experience and to help highlight navigation points.
When the user hovers the mouse over an image, the source of the image is modified, so that a different image appears.
When the user hovers the mouse back off the image, the original source is restored. The code below shows how to
create a simple rollover.

Code Sample: DynamicImages/Demos/SimpleRollover.html


<html>
<head>
<title>Simple Image Rollover</title>
</head>
<body>
<div style="text-align:center;">
<h1>Simple Image Rollover</h1>
<img name="MyImage" src="Images/Banner.jpg" border="0"
onmouseover="this.src = 'Images/Hulk.jpg';"
onmouseout="this.src = 'Images/Banner.jpg';">
<p>Who are you calling simple?</p>
</div>
</body>
</html>
Code Explanation

The mouse-over event is captured with the img tag's onmouseover event handler. When this happens, the following
JavaScript code is called.

this.src = 'Images/Hulk.jpg';

The this object refers to the current object - whatever object (or element) the this keyword appears in. In the case
above, the this object refers to the img object, which has a property called src that holds the path to the image. The code
above sets the src to "Images/Hulk.jpg".

Likewise, the mouse-out event is captured with the img tag's onmouseout event handler. When this happens, the
following JavaScript code is called.

this.src = 'Images/Banner.jpg';

This code sets the src to "Images/Banner.jpg," which is what it originally was.

Backward Compatibility

The code above should work fine in Firefox, Internet Explorer 4.0 and later, and Netscape 6 and later. However, in
earlier versions of browsers, images could not capture mouse events. The workaround is to wrap the <img> tag in an
<a> tag and to put the event handlers in the <a> tag as shown below.
Code Sample: DynamicImages/Demos/SimpleRollover-backward.html
<html>
<head>
<title>Simple Image Rollover</title>
</head>
<body>
<div style="text-align:center;">
<h1>Simple Image Rollover</h1>
<a href="#"
onmouseover="document.MyImage.src = 'Images/Hulk.jpg';"
onmouseout="document.MyImage.src = 'Images/Banner.jpg';">
<img name="MyImage" src="Images/Banner.jpg" border="0"></a>
<p>Who are you calling simple?</p>
</div>
</body>
</html>

An Image Rollover Function

Image rollovers can be handled by a function as well. The two examples below show an image rollover function for
modern browsers and a backward-compatible image rollover function.

Code Sample: DynamicImages/Demos/SimpleRolloverFunction.html


<html>
<head>
<title>Simple Image Rollover Function</title>
<script type="text/javascript">
function imageRollover(img, imgSrc){
img.src = imgSrc;
}
</script>
</head>
<body>
<div style="text-align:center;">
<h1>Simple Image Rollover Function</h1>
<img name="Banner" src="Images/Banner.jpg" border="0"
onmouseover="imageRollover(this, 'Images/Hulk.jpg');"
onmouseout="imageRollover(this, 'Images/Banner.jpg');">
<img name="Bruce" src="Images/Bruce.jpg" border="0"
onmouseover="imageRollover(this, 'Images/Batman.jpg');"
onmouseout="imageRollover(this, 'Images/Bruce.jpg');">
<p>Who are you calling simple?</p>
</div>
</body>
</html>

Code Sample: DynamicImages/Demos/SimpleRolloverFunction-backward.html


<html>
<head>
<title>Simple Image Rollover Function</title>
<script type="text/javascript">
function imageRollover(imgName, imgSrc){
if (document.images) {
document.images[imgName].src = imgSrc;
}
}
</script>
</head>
<body>
<div style="text-align:center;">
<h1>Simple Image Rollover Function</h1>
<a href="#"
onmouseover="imageRollover('MyImage', 'Images/Hulk.jpg');"
onmouseout="imageRollover('MyImage', 'Images/Banner.jpg');">
<img name="MyImage" src="Images/Banner.jpg" border="0"></a>
<p>Who are you calling simple?</p>
</div>
</body>
</html>
Code Explanation

Why the check for document.images? Some early versions of browsers don't support the images array.

Preloading Images
When working with files on a local machine, image rollovers like the ones we have seen in previous examples work
just fine. However, when the user first hovers over an image rollover image, the new image file has to be found and
delivered to the page. If the new image is on a far-away server, this can take a few moments, causing an ugly pause in
the rollover effect. This can be prevented by preloading images.

Images can be preloaded by creating an Image object with JavaScript and assigning a value to the src of that Image. A
sample is shown below.

Code Sample: DynamicImages/Demos/PreloadingImages.html


<html>
<head>
<title>Preloading Images</title>
<script type="text/javascript">

var IMAGE_PATHS = [];


IMAGE_PATHS[0] = "Images/Hulk.jpg";
IMAGE_PATHS[1] = "Images/Batman.jpg";

var IMAGE_CACHE = [];

for (var i=0; i<IMAGE_PATHS.length; i++) {


IMAGE_CACHE[i] = new Image();
IMAGE_CACHE[i].src = IMAGE_PATHS[i];
}

function imageRollover(img, imgSrc) {


img.src = imgSrc;
}
</script>
</head>
<body>
<div style="text-align:center;">
<h1>Simple Image Rollover Function</h1>
<img name="Banner" src="Images/Banner.jpg" border="0"
onmouseover="imageRollover(this, 'Images/Hulk.jpg');"
onmouseout="imageRollover(this, 'Images/Banner.jpg');">
<img name="Bruce" src="Images/Bruce.jpg" border="0"
onmouseover="imageRollover(this, 'Images/Batman.jpg');"
onmouseout="imageRollover(this, 'Images/Bruce.jpg');">
<p>Who are you calling simple?</p>
</div>
</body>
</html>
Code Explanation

Notice that the code is not in a function. It starts working immediately as follows:

1. An array called IMAGE_PATHS is created to hold the paths to the images that need to be preloaded.

var IMAGE_PATHS = [];

2. An array element is added for each image to be be preloaded.


3. IMAGE_PATHS[0] = "Images/Hulk.jpg";
IMAGE_PATHS[1] = "Images/Batman.jpg";

4. An array called IMAGE_CACHE is created to hold the Image objects that will hold the preloaded images.

var IMAGE_CACHE = [];


5. A for loop is used to create an Image object and load in an image for each image path in IMAGE_PATHS.
6. for (var i=0; i<IMAGE_PATHS.length; i++) {
7. IMAGE_CACHE[i]=new Image();
8. IMAGE_CACHE[i].src=IMAGE_PATHS[i];
}

Exercise: Creating a Slide Show

Duration: 20 to 30 minutes.

In this exercise, you will practice working with images by creating a slide show.

1. Open DynamicImages/Exercises/SlideShow.html for editing.


2. Write code to preload Images/Banner.jpg, Images/Hulk.jpg, Images/Bruce.jpg, and Images/Batman.jpg. The
paths to the images should be stored in an array called IMAGE_PATHS. The Image objects should be stored
in an array called IMAGE_CACHE.
3. Create a function called changeSlide() that takes one parameter: dir, and behaves as follows:
o If dir equals 1, it changes the slide to the next image as stored in the IMAGE_PATHS array.
o If dir equals -1, it changes the slide to the previous image as stored in the IMAGE_PATHS array.
o If the user is viewing the last slide and clicks the Next button, the first slide should appear.
o If the user is viewing the first slide and clicks the Previous button, the last slide should appear.
4. Test your solution in a browser.

1. Add a dropdown menu below the Previous and Next buttons that contains the names of the images without
their extensions: "Banner", "Hulk", "Bruce" and "Batman".
2. When the user selects an image from the dropdown, have that image appear above.
3. When the user changes the image above using the Previous and Next buttons, have the dropdown menu keep
in sync (i.e, show the name of the current image).

The solution should look like the screenshot below.

Where is the solution?

Working with Images Conclusion


In this lesson of the JavaScript tutorial, you have learned how JavaScript can be used to manipulate HTML images to
create image rollover effects and slide shows.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Regular Expressions
In this lesson of the JavaScript tutorial, you will learn...

1. To use regular expressions for advanced form validation.


2. To use regular expressions and backreferences to clean up form entries.

Getting Started
Regular expressions are used to do sophisticated pattern matching, which can often be helpful in form validation. For
example, a regular expression can be used to check whether an email address entered into a form field is syntactically
correct. JavaScript supports Perl-compatible regular expressions.

There are two ways to create a regular expression in JavaScript:

1. Using literal syntax

var reExample = /pattern/;

2. Using the RegExp() constructor

var reExample = new RegExp("pattern");

Assuming you know the regular expression pattern you are going to use, there is no real difference between the two;
however, if you don't know the pattern ahead of time (e.g, you're retrieving it from a form), it can be easier to use the
RegExp() constructor.

JavaScript's Regular Expression Methods

The regular expression method in JavaScript has two main methods for testing strings: test() and exec().

The exec() Method

The exec() method takes one argument, a string, and checks whether that string contains one or more matches of the
pattern specified by the regular expression. If one or more matches is found, the method returns a result array with the
starting points of the matches. If no match is found, the method returns null.

The test() Method

The test() method also takes one argument, a string, and checks whether that string contains a match of the pattern
specified by the regular expression. It returns true if it does contain a match and false if it does not. This method is very
useful in form validation scripts. The code sample below shows how it can be used for checking a social security
number. Don't worry about the syntax of the regular expression itself. We'll cover that shortly.

Code Sample: RegularExpressions/Demos/SsnChecker.html


<html>
<head>
<title>ssn Checker</title>
<script type="text/javascript">
var RE_SSN = /^[0-9]{3}[\- ]?[0-9]{2}[\- ]?[0-9]{4}$/;

function checkSsn(ssn){
if (RE_SSN.test(ssn)) {
alert("VALID SSN");
} else {
alert("INVALID SSN");
}
}
</script>
</head>
<body>
<form onsubmit="return false;">
<input type="text" name="ssn" size="20">
<input type="button" value="Check"
onclick="checkSsn(this.form.ssn.value);">
</form>
</body>
</html>
Code Explanation

Let's examine the code more closely:

1. First, a variable containing a regular expression object for a social security number is declared.

var RE_SSN = /^[0-9]{3}[\- ]?[0-9]{2}[\- ]?[0-9]{4}$/;

2. Next, a function called checkSsn() is created. This function takes one argument: ssn, which is a string. The
function then tests to see if the string matches the regular expression pattern by passing it to the regular
expression object's test() method. If it does match, the function alerts "VALID SSN". Otherwise, it alerts
"INVALID SSN".
3. function checkSsn(ssn){
4. if (RE_SSN.test(ssn)) {
5. alert("VALID SSN");
6. } else {
7. alert("INVALID SSN");
8. }
}

9. A form in the body of the page provides a text field for inserting a social security number and a button that
passes the user-entered social security number to the checkSsn() function.
10. <form onsubmit="return false;">
11. <input type="text" name="ssn" size="20">
12. <input type="button" value="Check"
13. onclick="checkSsn(this.form.ssn.value);">
</form>

Flags

Flags appearing after the end slash modify how a regular expression works.

• The i flag makes a regular expression case insensitive. For example, /aeiou/i matches all lowercase and
uppercase vowels.
• The g flag specifies a global match, meaning that all matches of the specified pattern should be returned.

String Methods

There are several String methods that use regular expressions.

The search() Method

The search() method takes one argument: a regular expression. It returns the index of the first character of the substring
matching the regular expression. If no match is found, the method returns -1.

"Webucator".search(/cat/); //returns 4

The split() Method


The split() method takes one argument: a regular expression. It uses the regular expression as a delimiter to split the
string into an array of strings.

"Webucator".split(/[aeiou]/);
/*
returns an array with the following values:
"W", "b", "c", "t", "r"
*/

The replace() Method

The replace() method takes two arguments: a regular expression and a string. It replaces the first regular expression
match with the string. If the g flag is used in the regular expression, it replaces all matches with the string.

"Webucator".replace(/cat/, "dog"); //returns Webudogor


"Webucator".replace(/[aeiou]/g, "x"); //returns Wxbxcxtxr

The match() Method

The match() method takes one argument: a regular expression. It returns each substring that matches the regular
expression pattern.

"Webucator".match(/[aeiou]/g);
/*
returns an array with the following values:
"e", "u", "a", "o"
*/

Regular Expression Syntax


A regular expression is a pattern that specifies a list of characters. In this section, we will look at how those characters
are specified.

Start and End ( ^ $ )

A caret (^) at the beginning of a regular expression indicates that the string being searched must start with this pattern.

• The pattern ^foo can be found in "food", but not in "barfood".

A dollar sign ($) at the end of a regular expression indicates that the string being searched must end with this pattern.

• The pattern foo$ can be found in "curfoo", but not in "food".

Number of Occurrences ( ? + * {} )

The following symbols affect the number of occurrences of the preceding character: ?, +, *, and {}.

A questionmark (?) indicates that the preceding character should appear zero or one times in the pattern.

• The pattern foo? can be found in "food" and "fod", but not "faod".

A plus sign (+) indicates that the preceding character should appear one or more times in the pattern.

• The pattern fo+ can be found in "fod", "food" and "foood", but not "fd".
A asterisk (*) indicates that the preceding character should appear zero or more times in the pattern.

• The pattern fo*d can be found in "fd", "fod" and "food".

Curly brackets with one parameter ( {n} ) indicate that the preceding character should appear exactly n times in the
pattern.

• The pattern fo{3}d can be found in "foood" , but not "food" or "fooood".

Curly brackets with two parameters ( {n1,n2} ) indicate that the preceding character should appear between n1 and n2
times in the pattern.

• The pattern fo{2,4}d can be found in "food","foood" and "fooood", but not "fod" or "foooood".

Curly brackets with one parameter and an empty second paramenter ( {n,} ) indicate that the preceding character
should appear at least n times in the pattern.

• The pattern fo{2,}d can be found in "food" and "foooood", but not "fod".

Common Characters ( . \d \D \w \W \s \S )

A period ( . ) represents any character except a newline.

• The pattern fo.d can be found in "food", "foad", "fo9d", and "fo*d".

Backslash-d ( \d ) represents any digit. It is the equivalent of [0-9].

• The pattern fo\dd can be found in "fo1d", "fo4d" and "fo0d", but not in "food" or "fodd".

Backslash-D ( \D ) represents any character except a digit. It is the equivalent of [^0-9].

• The pattern fo\Dd can be found in "food" and "foad", but not in "fo4d".

Backslash-w ( \w ) represents any word character (letters, digits, and the underscore (_) ).

• The pattern fo\wd can be found in "food", "fo_d" and "fo4d", but not in "fo*d".

Backslash-W ( \W ) represents any character except a word character.

• The pattern fo\Wd can be found in "fo*d", "fo@d" and "fo.d", but not in "food".

Backslash-s ( \s) represents any whitespace character (e.g, space, tab, newline, etc.).

• The pattern fo\sd can be found in "fo d", but not in "food".

Backslash-S ( \S ) represents any character except a whitespace character.

• The pattern fo\Sd can be found in "fo*d", "food" and "fo4d", but not in "fo d".

Grouping ( [] )
Square brackets ( [] ) are used to group options.

• The pattern f[aeiou]d can be found in "fad" and "fed", but not in "food", "faed" or "fd".
• The pattern f[aeiou]{2}d can be found in "faed" and "feod", but not in "fod", "fed" or "fd".

Negation ( ^ )

When used after the first character of the regular expression, the caret ( ^ ) is used for negation.

• The pattern f[^aeiou]d can be found in "fqd" and "f4d", but not in "fad" or "fed".

Subpatterns ( () )

Parentheses ( () ) are used to capture subpatterns.

• The pattern f(oo)?d can be found in "food" and "fd", but not in "fod".

Alternatives ( | )

The pipe ( | ) is used to create optional patterns.

• The pattern foo$|^bar can be found in "foo" and "bar", but not "foobar".

Escape Character ( \ )

The backslash ( \ ) is used to escape special characters.

• The pattern fo\.d can be found in "fo.d", but not in "food" or "fo4d".

Backreferences
Backreferences are special wildcards that refer back to a subpattern within a pattern. They can be used to make sure
that two subpatterns match. The first subpattern in a pattern is referenced as \1, the second is referenced as \2, and so
on.

For example, the pattern ([bmpw])o\1 matches “bob†, “mom†, “pop†, and
“wow†, but not "bop" or "pow".

A more practical example has to do matching the delimiter in social security numbers. Examine the following regular
expression.

^\d{3}([\- ]?)\d{2}([\- ]?)\d{4}$

Within the caret (^) and dollar sign ($), which are used to specify the beginning and end of the pattern, there are three
sequences of digits, optionally separated by a hyphen or a space. This pattern will be matched in all of following strings
(and more).

• 123-45-6789
• 123 45 6789
• 123456789
• 123-45 6789
• 123 45-6789
• 123-456789

The last three strings are not ideal, but they do match the pattern. Backreferences can be used to make sure that the
second delimiter matches the first delimiter. The regular expression would look like this.

^\d{3}([\- ]?)\d{2}\1\d{4}$

The \1 refers back to the first subpattern. Only the first three strings listed above match this regular expression.

Form Validation with Regular Expressions


Regular expressions make it easy to create powerful form validation functions. Take a look at the following example.

Code Sample: RegularExpressions/Demos/Login.html


<html>
<head>
<title>Login</title>
<script type="text/javascript">

var RE_EMAIL = /^(\w+[\-\.])*\w+@(\w+\.)+[A-Za-z]+$/;


var RE_PASSWORD = /^[A-Za-z\d]{6,8}$/;

function validate(form){
var email = form.Email.value;
var password = form.Password.value;
var errors = [];

if (!RE_EMAIL.test(email)) {
errors[errors.length] = "You must enter a valid email address.";
}

if (!RE_PASSWORD.test(password)) {
errors[errors.length] = "You must enter a valid password.";
}

if (errors.length > 0) {
reportErrors(errors);
return false;
}

return true;
}

function reportErrors(errors){
var msg = "There were some problems...\n";
for (var i = 0; i<errors.length; i++) {
var numError = i + 1;
msg += "\n" + numError + ". " + errors[i];
}
alert(msg);
}
</script>
</head>
<body>
<h1>Login Form</h1>
<form method="post" action="Process.html" onsubmit="return validate(this);">

Email: <input type="text" name="Email" size="25"><br/>


Password: <input type="password" name="Password" size="10"><br/>
*Password must be between 6 and 10 characters and
can only contain letters and digits.<br/>

<input type="submit" value="Submit">


<input type="reset" value="Reset Form">
</p>
</form>
</body>
</html>
Code Explanation
This code starts by defining regular expressions for an email address and a password. Let's break each one down.

var RE_EMAIL = /^(\w+\.)*\w+@(\w+\.)+[A-Za-z]+$/;

1. The caret (^) says to start at the beginning. This prevents the user from entering invalid characters at the
beginning of the email address.
2. (\w+[\-\.])* allows for a sequence of word characters followed by a dot or a dash. The * indicates that the
pattern can be repeated zero or more times. Successful patterns include "ndunn.", "ndunn-", "nat.s.", and "nat-
s-".
3. \w+ allows for one or more word characters.
4. @ allows for a single @ symbol.
5. (\w+\.)+ allows for a sequence of word characters followed by a dot. The + indicates that the pattern can be
repeated one or more times. This is the domain name without the last portion (e.g, without the "com" or
"gov").
6. [A-Za-z]+ allows for one or more letters. This is the "com" or "gov" portion of the email address.
7. The dollar sign ($) says to end here. This prevents the user from entering invalid characters at the end of the
email address.

var RE_PASSWORD = /^[A-Za-z\d]{6,8}$/;

1. The caret (^) says to start at the beginning. This prevents the user from entering invalid characters at the
beginning of the password.
2. [A-Za-z\d]{6,8} allows for a six- to eight-character sequence of letters and digits.
3. The dollar sign ($) says to end here. This prevents the user from entering invalid characters at the end of the
password.

Exercise: Advanced Form Validation

Duration: 25 to 40 minutes.

1. Open RegularExpressions/Exercises/FormValidation.js for editing.


o Write additional regular expressions to check for:
1. Proper Name
ƒ starts with capital letter
ƒ followed by one or more letters or apostophes
ƒ may be multiple words (e.g, "New York City")
2. Initial
ƒ zero or one capital letters
3. State
ƒ two capital letters
4. US Postal Code
ƒ five digits (e.g, "02138")
ƒ possibly followed by a dash and four digits (e.g, "-1234")
5. Username
ƒ between 6 and 15 letters or digits
2. Open RegularExpressions/Exercises/Register.html for editing.
o Add validation to check the following fields:
1. first name
2. middle initial
3. last name
4. city
5. state
6. zip
7. username
3. Test your solution in a browser.

1. Add regular expressions to test Canadian and United Kingdom postal codes:
o Canadian Postal Code - A letter followed by a digit, a letter, a space, a digit, a letter, and a digit
(e.g, M1A 1A1)
o United Kingdom Postal Code - One or two letters followed by a digit, an optional letter, a space, a
digit, and two letters (e.g, WC1N 3XX)
2. Modify Register.html to check the postal code against these two new regular expressions as well as the
regular expression for a US postal code.

Where is the solution?

Cleaning Up Form Entries


It is sometimes nice to clean up user entries immediately after they are entered. This can be done using a combination
of regular expressions and the replace() method of a string object.

The replace() Method Revisited

Earlier, we showed how the replace() method of a string object can be used to replace regular expression matches with
a string. The replace() method can also be used with backreferences to replace a matched pattern with a new string
made up of substrings from the pattern. The example below illustrates this.

Code Sample: RegularExpressions/Demos/SsnCleaner.html


<html>
<head>
<title>ssn Cleaner</title>
<script type="text/javascript">
var RE_SSN = /^(\d{3})[\- ]?(\d{2})[\- ]?(\d{4})$/;

function cleanSsn(ssn){
if (RE_SSN.test(ssn)) {
var cleanedSsn = ssn.replace(RE_SSN, "$1-$2-$3");
return cleanedSsn;
} else {
alert("INVALID SSN");
return ssn;
}
}
</script>
</head>
<body>
<form onsubmit="return false;">
<input type="text" name="ssn" size="20">
<input type="button" value="Clean SSN"
onclick="this.form.ssn.value = cleanSsn(this.form.ssn.value);">
</form>
</body>
</html>
Code Explanation

The cleanSsn() function is used to "clean up" a social security number. The regular expression contained in RE_SSN,
^(\d{3})[\- ]?(\d{2})[\- ]?(\d{4})$, contains three subexpressions: (\d{3}), (\d{2}), and (\d{4}). Within the replace()
method, these subexpressions can be referenced as $1, $2, and $3, respectively.

When the user clicks on the "Clean SSN" button, the cleanSsn() function is called. This function first tests to see that
the user-entered value is a valid social security number. If it is, it then cleans it up with the line of code below, which
dash-delimits the three substrings matching the subexpressions.

var cleanedSsn = ssn.replace(RE_SSN, "$1-$2-$3");

It then returns the cleaned-up social security number.

Exercise: Cleaning Up Form Entries

Duration: 15 to 25 minutes.
1. Open RegularExpressions/Exercises/PhoneCleaner.html for editing.
2. Where the comment indicates, declare a variable called cleanedPhone and assign it a cleaned-up version of
the user-entered phone number. The cleaned up version should fit the following format: (555) 555-1212
3. Test your solution in a browser.

Some phone numbers are given as a combination of numbers and letters (e.g, 877-WEBUCATE). As is the case with
877-WEBUCATE, such numbers often have an extra character just to make the word complete.

1. Add a function called convertPhone() that:


o strips all characters that are not numbers or letters
o converts all letters to numbers
ƒ ABC -> 2
ƒ DEF -> 3
ƒ GHI -> 4
ƒ JKL -> 5
ƒ MNO -> 6
ƒ PRS -> 7
ƒ TUV -> 8
ƒ WXY -> 9
ƒ QZ -> 0
o passes the first 10 characters of the resulting string to the cleanPhone() function
o returns the resulting string
2. Modify the form, so that it calls convertPhone() rather than cleanPhone().
3. Test your solution in a browser.

Where is the solution?

Regular Expressions Conclusion


In this lesson of the JavaScript tutorial, you have learned to work with regular expressions to validate and to clean up
form entries.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Jump Menus
A jump menu is a select menu that contains a list of websites or pages to visit. There are two main types of jump
menus. One jumps to the selected page as soon as the user makes a selection. The other jumps to a page only after the
user has made a selection and clicked on a "Go" button. We'll look at the latter type first and then create the former type
in an exercise.

Code Sample: DynamicForms/Demos/JumpMenus.html


<html>
<head>
<title>Jump Menus</title>
<script type="text/javascript">
function jumpMenu(select){
var i = select.selectedIndex;
var selection = select.options[i].value;
var url;
if (i === 0) {
alert("Please select a state.");
} else {
url = "http://www.50states.com/" + selection + ".htm";
location.href = url;
}
}
</script>
</head>
<body>
<form>
<select name="State">
<option value="0">--SELECT A STATE--</option>
<option value="alabama">Alabama</option>
<option value="illinois">Illinois</option>
<option value="massachu">Massachusetts</option>
<option value="montana">Montana</option>
<option value="ncarolin">North Carolina</option>
<option value="wvirgini">West Virginia</option>
</select>
<input type="button" value="GO"
onclick="jumpMenu(this.form.State);">
</form>
</body>
</html>
Code Explanation

Viewed in a browser, the page looks like this:

The options[] Array

Select menus contain an array of options. Like with all JavaScript arrays, the first item has an index of 0. So, in this
example, the first option, which reads "--SELECT A STATE--" is option 0.

The selectedIndex Property

Select menus have a selectedIndex property that holds the index of the currently selected option. For example, in the
sample above, if North Carolina is selected, State.selectedIndex would hold 5. To see if the first option of a select menu
is selected, check if selectedIndex is 0.

Let's look at the code above in detail.

1. The "GO" button has an onclick event handler that, when clicked, passes the State select menu to the
jumpMenu() function.
<input type="button" value="GO" onclick="jumpMenu(this.form.State);">

2. The jumpMenu() function does three things:


1. Creates the variable i that holds the selectedIndex property of the passed-in select menu.
2. Creates the variable selection that holds the value of the selected option.
3. Checks to see if the first option is selected.
ƒ If it is, the function alerts the user to select an option.
ƒ If it is not, the function creates a variable, url, to hold the destination page and then loads
that page by changing the href property of the location object to url.

Disabling Form Elements

Form elements can be disabled by setting the element's disabled property to true. They can be re-enabled by setting the
disabled property to false.

Syntax
FormElement.disabled = true;
FormElement.disabled = false;

The example below is a modified version of the jump menu that disables the "GO" button unless a state is selected.

Code Sample: DynamicForms/Demos/JumpMenus2.html


<html>
<head>
<title>Jump Menus</title>
<script type="text/javascript">
function jumpMenu(select){
var i = select.selectedIndex;
var selection = select.options[i].value;
var url = "http://www.50states.com/" + selection + ".htm";
location.href = url;
}

function toggleButton(form){
if (form.State.selectedIndex === 0) {
form.btnJump.disabled = true;
} else {
form.btnJump.disabled = false;
}
}
</script>
</head>
<body onload="toggleButton(document.forms[0]);">
<form>
<select name="State" onChange="toggleButton(this.form);">
<option value="0">--SELECT A STATE--</option>
<option value="alabama">Alabama</option>
<option value="illinois">Illinois</option>
<option value="massachu">Massachusetts</option>
<option value="montana">Montana</option>
<option value="ncarolin">North Carolina</option>
<option value="wvirgini">West Virginia</option>
</select>
<input type="button" name="btnJump" value="GO"
onclick="jumpMenu(this.form.State);">
</form>
</body>
</html>
Code Explanation

Notice that the jumpMenu() function no longer checks if a state has been selected. It is only called when the user clicks
the "Go" button, which is only enabled if a state is selected.

Exercise: Modifying the Jump Menu

Duration: 15 to 25 minutes.
In this exercise, you will modify the jump menu from the demo so that it jumps to the selected page as soon as the user
makes a selection.

1. Open DynamicForms/Exercises/JumpMenus.html for editing.


2. Add an onchange event handler to the select menu that calls jumpMenu() and passes in itself.
3. Modify the function so that it no longer alerts the user when the first option is selected.
4. Remove the "GO" button from the form.
5. Test the solution in a browser.

The jumpMenu() function isn't reusable. Why not? Fix the function so that it is portable and then modify the form
accordingly.

Where is the solution?

Interdependent Select Menus


Interdependent select menus allow you to populate one select menu based on a choice made in another select menu. For
example, a menu of cities might change based on the state that was selected in another menu, as shown in the following
example.

Code Sample: DynamicForms/Demos/Interdependent.html


<html>
<head>
<title>Interdependent Select Menus</title>
<script type="text/javascript">
var NEW_YORKERS = [];
var CALIFORNIANS = [];

NEW_YORKERS[0] = new Option("New York City", "NYC");


NEW_YORKERS[1] = new Option("Syracuse", "SYR");
NEW_YORKERS[2] = new Option("Albany", "ALB");
NEW_YORKERS[3] = new Option("Rochester", "ROC");

CALIFORNIANS[0] = new Option("Los Angeles", "LAN");


CALIFORNIANS[1] = new Option("San Diego", "SDI");
CALIFORNIANS[2] = new Option("San Francisco", "SFR");
CALIFORNIANS[3] = new Option("Oakland", "OAK");

function populateSub(mainSel, subSel){


var mainMenu = mainSel;
var subMenu = subSel;
var subMenuItems;
subMenu.options.length = 0;

switch (mainMenu.selectedIndex) {
case 0:
subMenuItems = NEW_YORKERS;
break;
case 1:
subMenuItems = CALIFORNIANS;
break;
}

for (var i = 0; i < subMenuItems.length; i++) {


subMenu.options[i] = subMenuItems[i];
}
}

</script>
</head>
<body>
<form name="Menus">
<select name="State" onchange="populateSub(this, this.form.City);">
<option value="NY">New York</option>
<option value="CA">California</option>
</select>
<select name="City">
<option value="NYC">New York City</option>
<option value="SYR">Syracuse</option>
<option value="ALB">Albany</option>
<option value="ROC">Rochester</option>
</select>
</form>
</body>
</html>
Code Explanation

Let's look at the code above in detail.

1. As the page loads, two arrays (NEW_YORKERS and CALIFORNIANS) are created and then populated with
Options using the Option() constructor. The Option() constructor takes four parameters: text, value,
defaultSelected, and selected. Only text is required.
2. The body of the page contains a form with two select menus: State and City. When a state is selected, the
onchange event handler triggers a call to the populateSub() function, passing in the State menu as mainSel
and the City menu as subSel.
3. A few variables are created and then the City menu is emptied with the following code.

subMenu.options.length = 0;

4. A switch statement based on the option selected in the main menu is used to determine the array to look in for
the submenu's options.
5. switch (mainMenu.selectedIndex) {
6. case 0:
7. arrSubMenu = NEW_YORKERS;
8. break;
9. case 1:
10. arrSubMenu = CALIFORNIANS;
11. break;
}

12. A for loop is used to loop through the array populating the submenu with options.

Making the Code Modular

A problem with the code in DynamicForms/Demos/Interdependent.html is that it would need to be modified in several
places to add or change options. This next example, though more complex, is much more modular, and hence, reusable.

Code Sample: DynamicForms/Demos/Interdependent2.html


<html>
<head>
<title>Interdependent Select Menus</title>
<script type="text/javascript">
var MENU = [];
MENU[0] = [];
MENU[1] = [];

MENU[0][0] = new Option("New York", "NY");


MENU[0][1] = new Option("New York City", "NYC");
MENU[0][2] = new Option("Syracuse", "SYR");
MENU[0][3] = new Option("Albany", "ALB");
MENU[0][4] = new Option("Rochester", "ROC");

MENU[1][0] = new Option("California", "CA");


MENU[1][1] = new Option("Los Angeles", "LAN");
MENU[1][2] = new Option("San Diego", "SDI");
MENU[1][3] = new Option("San Francisco", "SFR");
MENU[1][4] = new Option("Oakland", "OAK");

function populateMain(mainSel, subSel){


var mainMenu = mainSel;
var subMenu = subSel;
mainMenu.options.length = 0;
for (var i = 0; i < MENU.length; i++) {
mainMenu.options[i] = MENU[i][0];
}
populateSub(mainMenu, subMenu);
}
function populateSub(mainSel, subSel){
var mainMenu = mainSel;
var subMenu = subSel;
var optMainMenu;
subMenu.options.length = 1;
optMainMenu = mainMenu.selectedIndex;
for (var i = 1; i < MENU[optMainMenu].length; i++) {
subMenu.options[i] = MENU[optMainMenu][i];
}
}
</script>
</head>
<body onload="populateMain(document.Menus.State, document.Menus.City);">
<form name="Menus">
<select name="State" onchange="populateSub(this, this.form.City);"></select>
<select name="City">
<option value="0">--Please Choose--</option>
</select>
</form>
</body>
</html>
Code Explanation

This example uses a two-dimensional array to hold the menus. The first item of each array holds the State options,
which is used in the main menu. The rest of the items in each array hold the City options used to populate the submenu.

The State select menu starts out empty and the City menu starts out with just a single "Please Choose" option. The two
functions populateMain() and populateSub() are used to populate the two menus. Both functions are completely generic
and reusable.

Exercise: Creating Interdependent Select Menus

Duration: 20 to 30 minutes.

In this exercise, you will modify DynamicForms/Exercises/Interdependent.html, so that the second select menu is
dependent on the first.

1. Open DynamicForms/Exercises/Interdependent.html for editing.


2. Notice that an external JavaScript file, Select.js, is included. This file is shown below.
3. An array, MENU, is created and populated with four internal arrays: MENU[0], MENU[1], MENU[2], and
MENU[3].
4. Populate the arrays so that:
o The Bands select menu will be populated with "Beatles", "Rolling Stones", "Genesis", and
"Eagles".
o When "Beatles" is chosen from the Bands select menu, the Artists select menu contains:
ƒ Paul McCartney with the value of "http://www.paulmccartney.com"
ƒ John Lennon with the value of "http://www.johnlennon.it"
ƒ George Harrison with the value of "http://www.georgeharrison.com"
ƒ Ringo Starr with the value of "http://www.ringostarr.com"
o When "Rolling Stones" is chosen, the Artists select menu contains:
ƒ Mick Jagger with the value of "http://www.mickjagger.com"
ƒ Keith Richards with the value of "http://www.keithrichards.com"
ƒ Charlie Watts with the value of "http://www.rosebudus.com/watts"
ƒ Bill Wyman with the value of "http://www.billwyman.com"
o When "Genesis" is chosen, the Artists select menu contains:
ƒ Phil Collins with the value of "http://www.philcollins.co.uk"
ƒ Peter Gabriel with the value of "http://www.petergabriel.com"
ƒ Mike Rutherford with the value of "http://www.mikemechanics.com"
o When "Eagles" is chosen, the Artists select menu contains:
ƒ Don Henley with the value of "http://www.donhenley.com"
ƒ Joe Walsh with the value of "http://www.joewalsh.com"
ƒ Glenn Frey with the value of "http://www.imdb.com/name/nm0004940"
5. Change the values of arg1 and arg2 in the calls to populateMain() and populateSub() in the event handlers in
the HTML code so that the correct arguments are passed to these functions.

Code Sample: DynamicForms/Exercises/Select.js


function populateMain(mainSel, subSel){
var mainMenu = mainSel;
var subMenu = subSel;
mainMenu.options.length = 0;
for (var i = 0; i < MENU.length; i++) {
mainMenu.options[i] = MENU[i][0];
}
populateSub(mainMenu, subMenu);
}

function populateSub(mainSel, subSel){


var mainMenu = mainSel;
var subMenu = subSel;
var optMainMenu;
subMenu.options.length = 1;
optMainMenu = mainMenu.selectedIndex;
for (var i = 1; i < MENU[optMainMenu].length; i++) {
subMenu.options[i] = MENU[optMainMenu][i];
}
}

function jumpMenu(select){
var i = select.selectedIndex;
var url = select.options[i].value;
if (i > 0) {
location.href = url;
}
}

Code Sample: DynamicForms/Exercises/Interdependent.html


<html>
<head>
<title>Interdependent Select Menus</title>
<script type="text/javascript" src="Select.js"></script>
<script type="text/javascript">
var MENU = [];
MENU[0] = [];
MENU[1] = [];
MENU[2] = [];
MENU[3] = [];

/*
Populate the arrays so that:
-The Bands select menu will be populated with
Beatles, Rolling Stones, Genesis, and Eagles

-When Beatles is chosen, the Artists select menu contains:


TEXT VALUE
Paul McCartney http://www.paulmccartney.com
John Lennon http://www.johnlennon.it
George Harrison http://www.georgeharrison.com
Ringo Starr http://www.ringostarr.com

-When Rolling Stones is chosen, the Artists select menu contains:


TEXT VALUE
Mick Jagger http://www.mickjagger.com
Keith Richards http://www.keithrichards.com
Charlie Watts http://www.rosebudus.com/watts
Bill Wyman http://www.billwyman.com

-When Genesis is chosen, the Artists select menu contains:


TEXT VALUE
Phil Collins http://www.philcollins.co.uk
Peter Gabriel http://www.petergabriel.com
Mike Rutherford http://www.mikemechanics.com

-When Eagles is chosen, the Artists select menu contains:


TEXT VALUE
Don Henley http://www.donhenley.com
Joe Walsh http://www.joewalsh.com
Glenn Frey http://www.imdb.com/name/nm0004940

Change the values of arg1 and arg2 in the calls to populateMain()


and populateSub() in the event handlers in the HTML code
so that the correct arguments are passed to these functions.
*/

</script>
</head>
<body onload="populateMain(arg1, arg2);">
<form name="Menus">
Band: <select name="Bands" onchange="populateSub(arg1, arg2);"></select>
Artist: <select name="Artists" onchange="jumpMenu(this);">
<option value="0">--Please Choose--</option>
</select>
</form>
</body>
</html>
Where is the solution?

Creating a JavaScript Timer


JavaScript timers can be used to create timed quizzes or events. The trick to a timer is to call a function recursively on a
time increment.

The setTimeout() Method

The window object's setTimeout() method is used to execute a block of JavaScript code every n milliseconds. The
syntax is shown below.

setTimeout("statements to execute", n);

Or

setTimeout(functionToCall, n);

The example below shows how the setTimeout() method can be used to create a timer.

Code Sample: DynamicForms/Demos/Timer.html


<html>
<head>
<title>JavaScript Timer</title>
<script type="text/javascript">

var SECONDS_LEFT, TIMER, TIMES_UP;


function init(){
document.Timer.btnStart.disabled = true;
}

function resetTimer(seconds){
SECONDS_LEFT = seconds;
document.Timer.TimeLeft.value = SECONDS_LEFT;
clearTimeout(TIMER);
document.Timer.btnStart.disabled = false;
document.Timer.btnReset.disabled = true;
}

function decrementTimer(){
TIMES_UP = false;
document.Timer.TimeLeft.value = SECONDS_LEFT;
document.Timer.btnStart.disabled = true;
document.Timer.btnReset.disabled = false;
SECONDS_LEFT--;
if (SECONDS_LEFT >= 0) {
TIMER = setTimeout(decrementTimer, 1000);
} else {
alert("Time's up!");
resetTimer(10);
}
}
</script>
</head>
<body onload="init();">
<form name="Timer" onsubmit="return false;">
Timer: <input type="text" name="TimeLeft" size="2"
style="text-align:center" onfocus="this.blur();">
seconds left<br>
<input type="button" name="btnStart"
value="Start" onclick="decrementTimer();">
<input type="button" name="btnReset"
value="Reset" onclick="resetTimer(10);">
</form>
</body>
</html>
Code Explanation

Let's look at the code above in detail.

1. As the page loads, three global variables are created: SECONDS_LEFT to hold the number of seconds left,
TIMER - to hold the timer, and TIMES_UP - to flag if the timer has run out.

var SECONDS_LEFT, TIMER, TIMES_UP;

2. The body of the page contains a form with a text field holding the number of seconds left, a "Start" button
and a "Reset" button.
3. <form name="Timer" onsubmit="return false;">
4. Timer: <input type="text" name="TimeLeft" size="2"
5. style="text-aliagn:center" onfocus="this.blur();">
6. seconds left<br>
7. <input type="button" name="btnStart"
8. value="Start" onclick="decrementTimer();">
9. <input type="button" name="btnReset"
10. value="Reset" onclick="resetTimer(10);">
</form>

11. The onload event handler of the body tag triggers the init() function, which disables the "Start" button.
12. function init(){
13. document.Timer.btnStart.disabled = true;
}

14. When the user clicks on the "Reset" button, the resetTimer() function is called. This function does the
following:
o Sets SECONDS_LEFT to the number passed into the function.

SECONDS_LEFT = seconds;

o Sets the value of the TimeLeft text field to SECONDS_LEFT.

document.Timer.TimeLeft.value = SECONDS_LEFT;

o Clears the TIMER timer.

clearTimeout(TIMER);

o Enables the "Start" button.

document.Timer.btnStart.disabled = false;

o Disables the "Reset" button.

document.Timer.btnReset.disabled = true;
15. When the user clicks on the "Start" button, the decrementTimer() function is called. This function does the
following:
o Sets TIMES_UP to false.

TIMES_UP = false;

o Sets the value of the TimeLeft text field to SECONDS_LEFT.

document.Timer.TimeLeft.value = SECONDS_LEFT;

o Disables the "Start" button.

document.Timer.btnStart.disabled = true;

o Enables the "Reset" button.

document.Timer.btnReset.disabled = false;

o Decrements SECONDS_LEFT by one.

SECONDS_LEFT--;

o Checks to see if SECONDS_LEFT is greater than or equal to zero.


o if (SECONDS_LEFT >= 0) {
o TIMER = setTimeout(decrementTimer, 1000);
o } else {
o alert("Times up!");
o resetTimer(10);
}

ƒ If SECONDS_LEFT is greater than or equal to zero, setTimeout() is used to re-call


decrementTimer() after 1000 milliseconds (1 second). This creates a timer object, which
is assigned to TIMER.
ƒ If SECONDS_LEFT is less than zero, an alert pops up notifying the user that time is up
and resetTimer(), which clears the timer, is called.

Exercise: Adding a "Pause" Button to the Timer

Duration: 10 to 20 minutes.

In this exercise, you will add a "Pause" button to the timer.

1. Open DynamicForms/Exercises/Timer.html for editing.


2. This page is the same as DynamicForms/Demos/Timer.html, except that it has a new "Pause" button that,
when clicked, calls the pauseTimer() function. Your job is to create this pauseTimer() function and to modify
the script so that the right buttons are enabled at the right times. The diagram below shows the four different

phases.
3. Test your solution in a browser.

Where is the solution?


A Sample Quiz Tool
The following example brings together the concepts learned in this lesson to create a quiz tool. The quiz looks like this:

Code Sample: DynamicForms/Demos/MathQuiz.html


<html>
<head>
<title>Math Quiz</title>
<script type="text/javascript" src="Select.js"></script>
<script type="text/javascript">

var MENU = [];


var SECONDS_LEFT, TIMER, TIMES_UP, TOTAL_TIME = 10;

function init(){
MENU[0] = [];
MENU[1] = [];
MENU[2] = [];
MENU[3] = [];

MENU[0][0] = new Option("Addition");


MENU[0][1] = new Option("5 + 4", "9");
MENU[0][2] = new Option("9 + 3", "12");
MENU[0][3] = new Option("7 + 12", "19");
MENU[0][4] = new Option("13 + 24", "37");

MENU[1][0] = new Option("Subtraction");


MENU[1][1] = new Option("5 - 1", "4");
MENU[1][2] = new Option("12 - 4", "8");
MENU[1][3] = new Option("23 - 11", "12");
MENU[1][4] = new Option("57 - 19", "38");

MENU[2][0] = new Option("Multiplication");


MENU[2][1] = new Option("1 * 3", "3");
MENU[2][2] = new Option("4 * 8", "32");
MENU[2][3] = new Option("7 * 12", "84");
MENU[2][4] = new Option("13 * 17", "221");

MENU[3][0] = new Option("Division");


MENU[3][1] = new Option("4 / 1", "4");
MENU[3][2] = new Option("12 / 3", "4");
MENU[3][3] = new Option("21 / 7", "3");
MENU[3][4] = new Option("121 / 11", "11");

populateMain(document.Quiz.Operator, document.Quiz.Question);
resetTimer(TOTAL_TIME);
document.Quiz.btnCheck.disabled = true;
document.Quiz.Answer.disabled = true;
}

function resetTimer(seconds){
TIMES_UP = true;
SECONDS_LEFT = seconds;
document.Quiz.TimeLeft.value = SECONDS_LEFT;
clearTimeout(TIMER);
document.Quiz.Answer.value = "";
}

function decrementTimer(){
TIMES_UP = false;
document.Quiz.TimeLeft.value = SECONDS_LEFT;
SECONDS_LEFT--;
if (SECONDS_LEFT >= 0) {
TIMER = setTimeout(decrementTimer, 1000);
} else {
alert("Time's up! The answer is " + getAnswer() + ".");
resetTimer(TOTAL_TIME);
}
}

function checkAnswer(answer){
var correctAnswer = getAnswer();
if (answer === correctAnswer) {
alert("Right! The answer is " + correctAnswer + ".");
} else {
alert("Sorry. The correct answer is " + correctAnswer + ".");
}
removeOption();
questionChange();
}

function removeOption(){
var i = document.Quiz.Operator.selectedIndex;
var j = document.Quiz.Question.selectedIndex;
MENU[i].splice(j, 1);
if (MENU[i].length == 1) {
MENU.splice(i, 1);
if (MENU.length === 0) {
endQuiz();
}
}
populateMain(document.Quiz.Operator, document.Quiz.Question);
resetTimer(TOTAL_TIME);
}

function questionChange(){
if (document.Quiz.Question.selectedIndex === 0) {
document.Quiz.btnCheck.disabled = true;
document.Quiz.Answer.disabled = true;
resetTimer(TOTAL_TIME);
} else {
document.Quiz.btnCheck.disabled = false;
document.Quiz.Answer.disabled = false;
decrementTimer();
}
}

function endQuiz(){
resetTimer(TOTAL_TIME);
alert("Thanks for playing! The quiz will now reload.");
init();
}

function getAnswer(){
var i = document.Quiz.Question.selectedIndex;
var answer = document.Quiz.Question[i].value;
return answer;
}

</script>
</head>
<body onload="init();">
<form name="Quiz" onsubmit="return false;">
<table border="1" cellspacing="0" cellpadding="4" align="center">
<tr>
<td>Category:</td>
<td>
<select name="Operator"
onchange="populateSub(this, this.form.Question);
resetTimer(TOTAL_TIME);">
</select>
</td>
</tr>
<tr>
<td>Question:</td>
<td>
<select name="Question"
onchange="questionChange();">
<option value="0">--Please Choose--</option>
</select>
</td>
</tr>
<tr>
<td>Answer:</td>
<td>
<input type="text" name="Answer" size="2">
<input type="button" name="btnCheck" value="Check Answer"
onclick="checkAnswer(this.form.Answer.value);">
</td>
</tr>
<tr>
<td>Timer:</td>
<td><input type="text" name="TimeLeft" size="2"
style="text-align:center" onfocus="this.blur();">
seconds left</td>
</tr>
</table>
</form>
</body>
</html>
Code Explanation

Here's how the quiz works:

1. The Question select menu is always populated with questions in the indicated category.
2. The "Check Answer" button and the Answer text field are only enabled when a question is selected.
3. The timer starts when a question is selected and stops when it runs out or when the "Check Answer" button is
clicked.
4. When the "Check Answer" button is clicked, the user is alerted as to whether or not the answer is correct and
the question is removed from the question menu.
5. When all questions in a category are gone, the category is removed from the category menu.
6. When all questions in all categories have been completed, the user is thanked for taking the quiz and the
entire quiz is restarted.

Spend some time reviewing this code. You shouldn't see anything new, except in the way the code is designed.

Dynamic Forms Conclusion


In this lesson of the JavaScript tutorial, you have learned to build interactive, dynamic forms.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.

The User's Environment


In this lesson of the JavaScript tutorial, you will learn...

1. To detect the user's operating system.


2. To detect browser information.
3. To determine if the user's browser supports a specific feature.
4. To determine if Cookies are turned off.

Why Know the User's Environment?


Although browsers have come a long way in the past several years, they unfortunately do not all support the W3C
specifications to the same degree. When writing sophisticated code that is intended to work across multiple browsers
and platforms, it is often necessary to branch the code for the different environments.

A very good way to manage this is to create a JavaScript file that stores many environment-related variables that hold
flags indicating the type of browser or support for a specific object, property or method.

The code below demonstrates how this file might be structured.

Code Sample: UserEnvironment/Demos/EnvVars.js


//Operating System
var IS_WIN = (navigator.userAgent.indexOf("Win") >= 0);
var IS_MAC = (navigator.userAgent.indexOf("Mac") >= 0);
var IS_UNIX = (navigator.userAgent.indexOf("X11") >= 0);
//Browser Info
var IS_IE = (navigator.appName == "Microsoft Internet Explorer");
var IS_FF = (navigator.userAgent.indexOf("Firefox") >= 0);
var IS_NS = (navigator.vendor != "undefined" &&
navigator.vendor == "Netscape");
var IS_MOZ = (navigator.userAgent.indexOf("Mozilla/5") >= 0);
var IS_NEW = ((IS_MOZ && parseInt(navigator.appVersion) >= 5) ||
(IS_IE && parseInt(navigator.appVersion) >= 4));

//Object Support
var SUPPORTS_IMAGES = (typeof document.images != "undefined");

//Cookies
var COOKIES_ON = navigator.cookieEnabled;

Examine UserEnvironment/Demos/UserEnvironment.html to see the properties of your environment.

Exercise: Checking if Cookies are Enabled

Duration: 10 to 20 minutes.

In this exercise, you will modify a simple page so that it redirects a user to another page if cookies are not enabled.

1. Open UserEnvironment/Exercises/CookieCheck.html for editing.


2. Add JavaScript code so that the page checks to see if cookies are enabled. If they are, it should simply load. If
they are not, it should redirect to CookieApology.html. Note that you can use settings from EnvVars.js.
3. Test your solution in a browser. You may have to temporarily disable cookies to see the effect of your code.

Where is the solution?

The User's Environment Conclusion


In this brief lesson, you have learned to determine the settings and capabilities of a user's environment and to respond
accordingly.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.

All material in this The User's Environment is copyright 2010 Webucator. The purpose of this website is to help you
learn
Dynamic HTML
In this lesson of the JavaScript tutorial, you will learn...

1. To change the values of CSS properties dynamically.


2. To hide and show elements.
3. To dynamically modify the content fo elements.
4. To manipulate tables dynamically.
5. To position elements dynamically.
6. To change the z-index order of elements.

Introduction
Dynamic HTML is not a technology in and of itself, but rather is a combination of three technologies: HTML,
Cascading Style Sheets (CSS), and JavaScript. It usually involves using JavaScript to change a CSS property of an
HTML element. In modern browsers, most CSS properties can be modified dynamically. This can be done by changing
an individual style of element (using the style property of the element) or by changing the class name assigned to the
element (using the className property).

Accessing and Modifying Styles


The style object is a collection of an element's styles that are either defined within that HTML element's style attribute
or directly in JavaScript. Styles defined in the <style> tag or in an external style sheet are not part of the style object.
The W3C specifies a method for getting at the current (or actual) style of an object: the window object's
getComputedStyle() method, which is supported by the latest versions of Mozilla, but not by Internet Explorer 6 and
earlier. Internet Explorer provides a non-standard property for getting at the current style of an element: the
currentStyle property.

Standard Syntax

window.getComputedStyle(Element, Pseudo-Element)

//for example:
var curStyle = window.getComputedStyle(
document.getElementById("divTitle"), null);
alert(curStyle.fontWeight);

Internet Explorer Syntax

Element.currentStyle.Property
//for example:
alert(document.getElementById("divTitle").currentStyle.fontWeight);

Cross-browser Solution

var curStyle;
if (window.getComputedStyle) {
curStyle = window.getComputedStyle(
document.getElementById("divTitle"), "");
} else {
curStyle = document.getElementById("divTitle").currentStyle;
}
alert(curStyle.fontWeight);

Another solution is to use JavaScript to set the styles of the objects on the page.

function init(){
document.getElementById("divTitle").style.fontWeight = "bold";
}
Now this style can be referenced later in the script; however, this solution isn't always practical.

Hiding and Showing Elements


Elements can be hidden and shown by changing their visibility or display values. The visibility style can be set to
visible or hidden and the display property can be set to block, table-row, none, and several other values. The two work
slightly differently as the following example illustrates.

Code Sample: DynamicHtml/Demos/Visibility.html


<html>
<head>
<title>Showing and Hiding Elements with JavaScript</title>
<script type="text/javascript" src="EnvVars.js"></script>
<script type="text/javascript">

function changeVisibility(TR){
if (document.getElementById(TR).style.visibility=="hidden") {
document.getElementById(TR).style.visibility = "visible";
} else {
document.getElementById(TR).style.visibility = "hidden";
}
}

var TR_DISPLAY = (IS_IE) ? "block" : "table-row";

function changeDisplay(TR){
if (document.getElementById(TR).style.display == "none") {
document.getElementById(TR).style.display = TR_DISPLAY;
} else {
document.getElementById(TR).style.display = "none";
}
}
</script>
</head>
<body>
<h1>Hiding and Showing Elements</h1>
<table border="1">
<tr id="tr1"><td>tableElem Row 1</td></tr>
<tr id="tr2"><td>tableElem Row 2</td></tr>
<tr id="tr3"><td>tableElem Row 3</td></tr>
<tr id="tr4"><td>tableElem Row 4</td></tr>
</table>
<form>
<h2>visibility</h2>
<input type="button" onclick="changeVisibility('tr1')" value="TR1">
<input type="button" onclick="changeVisibility('tr2')" value="TR2">
<input type="button" onclick="changeVisibility('tr3')" value="TR3">
<input type="button" onclick="changeVisibility('tr4')" value="TR4">

<h2>display</h2>
<input type="button" onclick="changeDisplay('tr1')" value="TR1">
<input type="button" onclick="changeDisplay('tr2')" value="TR2">
<input type="button" onclick="changeDisplay('tr3')" value="TR3">
<input type="button" onclick="changeDisplay('tr4')" value="TR4">
</form>
</body>
</html>
Code Explanation

This page has two functions: changeVisibility() and changeDisplay(). The changeVisibility() function checks the value
of the visibility style of the passed element and changes it to its opposite. The changeDisplay() function does the same
with the display style. The functions are called with buttons on the page and are passed in ids of table rows from the
table on the page.

The main difference between setting visibility to hidden and setting display to none is that setting visibility to hidden
does not modify the layout of the page; it simply hides the element. Setting display to none, on the other hand,
collapses the element, so that the surrounding relatively positioned elements re-position themselves.
In the screenshot below, tableElem Row 1 has visibility set to hidden and tableElem Row 3 has display set to none.

The following line of code may have grabbed your attention:

var TR_DISPLAY = (IS_IE

) ? "block" : "table-row";

According to the CSS specification, the proper way to display a table row is by setting the display property to table-
row; however Internet Explorer 6 and earlier do not support this value. To get the script to behave correctly in IE6, the
display must be set to block; however, that messes up Mozilla, which displays blocks as blocks, not as table rows. The
solution is to create a variable, TR_DISPLAY, whose value depends on the browser being used. That's exactly what the
line of code above does.

Exercise: Showing and Hiding Elements

Duration: 20 to 30 minutes.

In this exercise, you will modify a Math Quiz to only show the countdown timer when it is running.

1. Open DynamicHtml/Exercises/MathQuiz.html for editing.


2. Modify the code so that the table row with the timer in it (the last row) only shows up when the timer is

running. Note that the variable TR_DISPLAY is already set to the proper browser-dependent value.

Hint: You will make your changes in resetTimer() and decrementTimer().


3. Test your solution in a browser.

Only show the Answer row when a question is selected.

Where is the solution?

The innerHTML Property


Internet Explorer 4+ and the latest Mozilla browsers (Netscape 6+ and Firefox) support the non-standard innerHTML
property of an element. The innerHTML property can be used to read and set the HTML content of an element. The
following example illustrates this.

Code Sample: DynamicHtml/Demos/innerHTML.html


<html>
<head>
<title>innerHTML</title>
</head>
<body>
<div id="divGreeting">
<h1>Hello!</h1>
</div>
<form>
<input type="button" value="Return Greeting"
onclick="document.getElementById('divGreetingBack').innerHTML =
document.getElementById('divGreeting').innerHTML;">
</form>
<div id="divGreetingBack"></div>
</body>
</html>
Code Explanation
When the user clicks the "Return Greeting" button, the HTML content of divGreeting is copied into divGreetingBack.

Exercise: Using innerHTML for Cleaner Messages

Duration: 10 to 20 minutes.

In this exercise, you will modify the Math Quiz so that it displays messages in plain text, rather than in form fields and
alerts.

1. Open DynamicHtml/Exercises/MathQuizInnerHTML.html for editing.


2. Replace the TimeLeft text field with a span with an id of "spanTimeLeft".
3. Beneath the form, add an empty div with the id of "divMessage".
4. Create a new function called showMessage(), which takes to arguments: the message to show and the color to
display it in. This function should do the following:
o Set the innerHTML property of divMessage to the passed-in message.
o Change the value of the color style of divMessage to the passed-in color.
o Display divMessage as a block.
5. Replace the two alerts in checkAnswer() with calls to showMessage(). Pass in green as the color if the answer
is correct and red if it is not.
6. You may find it useful to look at the decrementTimer() function, which already has some modifications.

Code Sample: DynamicHtml/Exercises/MathQuizInnerHTML.html


---- Code Omitted ----

function decrementTimer(){
TIMES_UP = false;
document.getElementById("trTimer").style.display = TR_DISPLAY;

document.getElementById("divMessage").innerHTML = "";
document.getElementById("divMessage").style.display = "none";

document.getElementById("spanTimeLeft").innerHTML=TIME_LEFT + " ";


document.getElementById("trTimer").style.visibility = "visible";

INTERVAL--;
if (TIME_LEFT >= 0) {
TIMER = setTimeout(decrementTimer, 1000);
} else {
showMessage("Time's up! The answer is " + getAnswer() + ".", "red");
resetTimer(INTERVAL);
}
}
---- Code Omitted ----

Where is the solution?

Manipulating Tables
HTML tables can be created and manipulated dynamically with JavaScript. Each table element contains a rows array
and methods for inserting and deleting rows: insertRow() and deleteRow(). Each tr element contains a cells array and
methods for inserting and deleting cells: insertCell() and deleteCell(). The following example shows how these objects
can be used to dynamically create HTML tables.

Code Sample: DynamicHtml/Demos/table.html


<html>
<head>
<title>Manipulating Tables</title>
<script type="text/javascript">
function addRow(tableId, cells){
var tableElem = document.getElementById(tableId);
var newRow = tableElem.insertRow(tableElem.rows.length);
var newCell;
for (var i = 0; i < cells.length; i++) {
newCell = newRow.insertCell(newRow.cells.length);
newCell.innerHTML = cells[i];
}
return newRow;
}

function deleteRow(tableId, rowNumber){


var tableElem = document.getElementById(tableId);
if (rowNumber > 0 && rowNumber < tableElem.rows.length) {
tableElem.deleteRow(rowNumber);
} else {
alert("Failed");
}
}
</script>
</head>

<body>
<table id="tblPeople" border="1">
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</table>
<hr>
<form name="formName">
First Name: <input type="text" name="FirstName"><br>
Last Name: <input type="text" name="LastName"><br>
<input type="button" value="Add Name"
onclick="addRow('tblPeople',
[this.form.FirstName.value, this.form.LastName.value] );">
<hr>
Remove Row: <input type="text" size="1" name="RowNum">
<input type="button" value="Delete Row"
onclick="deleteRow('tblPeople', this.form.RowNum.value)">
</form>
</body>
</html>
Code Explanation

The body of the page contains a table with an id of formName. The table contains a single row of headers.

<table id="tblPeople" border="1">


<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</table>

Below the table is a form that allows the user to enter a first and last name. When the "Add Name" button is clicked,
the addRow() function is called and passed in the id of the table (tblPeople) and a new array containing the user-entered
values.

First Name: <input type="text" name="FirstName"><br>


Last Name: <input type="text" name="LastName"><br>
<input type="button" value="Add Name"
onclick="addRow('tblPeople',
[this.form.FirstName.value, this.form.LastName.value] );">

The addRow() function uses the insertRow() method of the table to add a new row at the end of the table and then loops
through the passed-in array, creating and populating one cell for each item. The function also returns the new row.
Although the returned value isn't used in this example, it can be useful if you then want to manipulate the new row
further.

function addRow(tableId, cells){


var tableElem = document.getElementById(tableId);
var newRow = tableElem.insertRow(tableElem.rows.length);
var newCell;
for (var i = 0; i < cells.length; i++) {
newCell = newRow.insertCell(newRow.cells.length);
newCell.innerHTML = cells[i];
}
return newRow;
}

The form also contains a "Delete Row" button that, when clicked, passes the id of the table (tblPeople) and the number
entered by the user in the RowNum text field.

Remove Row: <input type="text" size="1" name="RowNum">


<input type="button" value="Delete Row"
onclick="deleteRow('tblPeople', this.form.RowNum.value)">

The deleteRow() function checks to see if the row specified exists and is not the first row (the header row). If both
conditions are true, it deletes the row. Otherwise, it alerts "Failed".

function deleteRow(tableId, rowNumber){


var tableElem = document.getElementById(tableId);
if (rowNumber > 0 && rowNumber < tableElem.rows.length) {
tableElem.deleteRow(rowNumber);
} else {
alert("Failed");
}
}

Exercise: Tracking Results in the Math Quiz

Duration: 15 to 25 minutes.

In this exercise, you will dynamically create a table that shows the user how she is doing on the Math Quiz. The

screenshot below shows how the result will look.

1. Open DynamicHtml/Exercises/MathQuizTable.html for editing.


2. Notice that the addRow() function is included and that there is an additional function called getQuestion(),
which returns the question that is currently selected.
3. Also notice that there is a table at the bottom of the body of the page with an id of tblResults.
4. Modify the checkAnswer() function so that it does the following:
o Creates an array to hold the current question and answer.
o Adds a new row to the tblResults table.
5. Test your solution in a browser.

Modify the code so that the new row's font color is green if the answer is correct and red if it is not. Hint: the addRow()
function returns the newly added row.

Where is the solution?

Dynamically Changing Dimensions


The dimensions of an object can be changed by modifying the width and height properties of the element's style
property. The following example demonstrates this.

Code Sample: DynamicHtml/Demos/Dimensions.html


<html>
<head>
<title>Dimensions</title>
<style type="text/css">
#divBlock {
height:100px;
width:100px;
background-color:red;
}
</style>
<script type="text/javascript">
function init(){
document.getElementById("divBlock").style.width = "100px";
document.getElementById("divBlock").style.height = "100px";
}

function grow(elem){
var objElem = elem;
var curWidth = parseInt(objElem.style.width);
var curHeight = parseInt(objElem.style.height);
objElem.style.width = (curWidth * 1.5) + 'px';
objElem.style.height = (curHeight * 1.5) + 'px';
}

function shrink(elem){
var objElem = elem;
var curWidth = parseInt(objElem.style.width);
var curHeight = parseInt(objElem.style.height);
objElem.style.width = (curWidth / 1.5) + 'px';
objElem.style.height = (curHeight / 1.5) + 'px';
}
</script>
</head>
<body onload="init();">
<div id="divBlock" onmouseover="grow(this);"
onmouseout="shrink(this);"></div>
</body>
</html>
Code Explanation

In this case, we use the init() function to set the height and width of the divBlock div, thus making the properties
accessible to JavaScript.

The grow() function uses parseInt() to cut off the units (e.g, px) from the value of the width and height of the div and
assign the resulting integers to variables: curWidth and curHeight. It then modifies the width and height properties of
the element by multiplying the current values by 1.5.

The shrink() function does the same thing, but it divides by 1.5 instead of multiplying.

The functions are triggered with onmouseover and onmouseout event handlers.

Creating a Timed Slider

The example below shows how a timed slider can be created by dynamically changing an element's dimensions.

Code Sample: DynamicHtml/Demos/Slider.html


<html>
<head>
<title>Slider</title>
<style type="text/css">
#divSlider {
height:10px;
width:0px;
background-color:red;
position:relative;
top:-11px;
left:1px;
}

#divSliderBG {
height:12px;
width:102px;
background-color:blue;
}
</style>
<script type="text/javascript">

var TIMER, TIMES_UP, Slider;


function resetTimer(){
TIMES_UP = true;
var slider = document.getElementById("divSlider");
slider.style.width = "0px";
clearTimeout(TIMER);
}

function decrementTimer(){
TIMES_UP = false;
var slider = document.getElementById("divSlider");
var curWidth = parseInt(slider.style.width);
if (curWidth < 100) {
slider.style.width = curWidth + 1 + "px";
TIMER = setTimeout(decrementTimer, 100);
} else {
alert("Time's up!");
resetTimer();
}
}
</script>
</head>

<body onload="resetTimer();">

<div id="divSliderBG"><img src="Images/Transparent.gif"


height="1" width="1"></div>
<div id="divSlider"><img src="Images/Transparent.gif"
height="1" width="1"></div>

<form>
<input type="button" value="Start Timer" onclick="decrementTimer();">
</form>

</body>
</html>

Positioning Elements Dynamically


The position of an object can be changed by modifying the left and top properties of the element's style property. The
following example demonstrates this.

Code Sample: DynamicHtml/Demos/Position.html


<html>
<head>
<title>Position</title>
<style type="text/css">
#divBlock {
position:relative;
height:100px;
width:100px;
top:100px;
left:100px;
background-color:red;
}
</style>
<script type="text/javascript">
function init(){
document.getElementById("divBlock").style.top = "100px";
document.getElementById("divBlock").style.left = "100px";
}

function moveH(elem, distance){


var objElem = document.getElementById(elem);
var curLeft = parseInt(objElem.style.left);
objElem.style.left = (curLeft + distance) + "px";
}

function moveV(elem, distance){


var objElem = document.getElementById(elem);
var curTop = parseInt(objElem.style.top);
objElem.style.top = (curTop + distance) + "px";
}
</script>
</head>
<body onload="init();">
<form>
<input type="button" value="Left" onclick="moveH('divBlock',-10);">
<input type="button" value="Right" onclick="moveH('divBlock',10);">
<input type="button" value="Up" onclick="moveV('divBlock',-10);">
<input type="button" value="Down" onclick="moveV('divBlock',10);">
</form>
<div id="divBlock"></div>
</body>
</html>
Code Explanation

We again use the init() function, this time to set the top and left properties of the divBlock div, thus making the
properties accessible to JavaScript.

The moveH() function uses parseInt() to cut off the units (e.g, px) from the value of the left property of the div and
assign the resulting integer to the curLeft variable. It then modifies the left property of the element by adding the value
passed in for distance.

The moveV() function does the same thing, but it modifies the top property rather than the left property.

The functions are triggered with onclick event handlers.

Creating a Different Timed Slider

The example below shows how a different type of timed slider can be created by dynamically changing an element's
position.

Code Sample: DynamicHtml/Demos/Slider2.html


<html>
<head>
<title>Slider</title>
<style type="text/css">
#divSlider {
height:10px;
width:2px;
background-color:red;
position:relative;
top:-11px;
left:1px;
}

#divSliderBG {
height:12px;
width:102px;
background-color:blue;
}
</style>
<script type="text/javascript">

var TIMER, TIMES_UP, Slider;


function resetTimer(){
TIMES_UP = true;
var slider = document.getElementById("divSlider");
slider.style.left = "1px";
clearTimeout(TIMER);
}

function decrementTimer(){
TIMES_UP = false;
var slider = document.getElementById("divSlider");
var curLeft = parseInt(slider.style.left);
if (curLeft < 100) {
slider.style.left = curLeft + 1 + "px";
TIMER = setTimeout(decrementTimer, 100);
} else {
alert("Time's up!");
resetTimer();
}
}
</script>
</head>

<body onload="resetTimer();">

<div id="divSliderBG"><img src="Images/Transparent.gif"


height="1" width="1"></div>
<div id="divSlider"><img src="Images/Transparent.gif"
height="1" width="1"></div>

<form>
<input type="button" value="Start Timer" onclick="decrementTimer();">
</form>

</body>
</html>

Exercise: Changing the Math Quiz Timer to a Slider

Duration: 15 to 25 minutes.

In this exercise, you will modify the Math Quiz so that the timer is a slider rather than a count down. The result will

look like this:

1. Open DynamicHtml/Exercises/MathQuizSlider.html for editing.


2. Notice that the timer on the page has been changed from an input element to two divs.
3. <tr id="trTimer">
4. <td>Timer:</td>
5. <td>
6. <div id="divSliderBG"><img src="Images/Transparent.gif"
7. height="1" width="1"></div>
8. <div id="divSlider"><img src="Images/Transparent.gif"
9. height="1" width="1"></div>
10. </td>
</tr>

11. Also notice that the resetTimer() function sets the width of the slider.
12. var slider = document.getElementById("divSlider");
slider.style.width = "0px";

13. Modify the decrementTimer() function as follows:


o Create a variable Slider that holds the divSlider object.
o Create a variable curWidth that holds the current width of the slider.
o Within the if block add 1 to the width of the slider.
14. Test your solution in a browser.

Modify the slider so that it extends the full width of the table cell it is within.

Where is the solution?

Changing the Z-Index

The z-index of an object can be changed by modifying the zIndex property of the element's style property. The
following example demonstrates this.

Code Sample: DynamicHtml/Demos/Zindex.html


<html>
<head>
<title>Position</title>
<style type="text/css">
#divRed {
position:relative;
height:100px;
width:100px;
z-index:10;
border:20px solid red;
}
#divBlue {
position:relative;
top:-50px;
height:100px;
width:100px;
z-index:20;
border:20px solid blue;
}
</style>
<script type="text/javascript">
var Z = 20;
function changeZ(elem){
Z += 10;
var objElem = elem;
elem.style.zIndex = Z;
}
</script>
</head>
<body>
<div id="divRed" onclick="changeZ(this);"></div>
<div id="divBlue" onclick="changeZ(this);"></div>
</body>
</html>
Code Explanation

The variable z always holds the highest z-index. The function changeZ() simply adds 10 to z and assigns the resulting
value to the zIndex property of the passed in object.

var Z = 20;
function changeZ(elem){
Z += 10;
var objElem = elem;
objElem.style.zIndex = Z;
}

Dynamic HTML Conclusion


In this lesson of the JavaScript tutorial, you have learned to dynamically modify the content of an HTML page and to
dynamically modify CSS styles of HTML elements.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Quick JavaScript Recap
In this lesson of the JavaScript tutorial, you will learn...

1. The basics of JavaScript in a context of a refresher.


2. The fundamental data types of JavaScript
3. That the DOM is not JavaScript
4. What is the main object behind AJAX

This is just a refresher


The intent of this lesson is not to replace more comprehensive JavaScript classes or books. As a matter of fact, this
lesson assumes you know your way around JavaScript but you may have forgotten one detail or two about the basics of
the language.

Here we will go quickly over the fundamental building blocks of JavaScript and try to clarify some concepts that
sometimes can be a little blurry.

Primitive data types


JavaScript comes with a number of data types that we can use in our variables. Let's look at them.

Null

Null is a data type that has only one possible value, null, which is also a reserved word in the language. We use null to
represent a value that we don't know or that is missing.

var name = "Homer";


var ssn = null;

In the above example we know what to put in the name variable but we don't know yet what to put in the ssn variable.
Maybe we will know what to put in there later in our program, but maybe not.

Undefined

The Undefined type also has a single value, undefined, and it is similar to null but not exactly the same thing.

JavaScript uses undefined as the default value for any variable that has not been initialized yet. Let's modify our
previous example.

var name = "Homer";


var ssn;

Now the value of ssn is undefined because it is no longer initialized to null or anything else.

The undefined type is used a lot when we want to detect if a global variable has been already declared. Which is kind of
a code smell anyway, as we will see in an upcoming lesson.

//Check if we already have a start time


if (START_TIME === undefined) {
START_TIME = new Date();
}
Boolean

Boolean is a very common data type in every language. It has only two values, true and false, which are reserved words
and, I hope, self-explanatory.

var enabled = true;


var disabled = false;

Number

The Number data type can represent two types of numeric values, 32-bit integers or 64-bit floating point numbers.

Number values are created using number literals, which can be in a few different formats.

var age = 25; // simple, decimal, integer


var price = 45.95; // floating point
var permissions = 0775; // integer in octal, 509 in decimal
// (note the leading zero)
var flags = 0x1c; // integer in hexadecimal, 28 in decimal
// (note the 0x prefix)
var measurement = 5.397e-9; // floating point in
// scientific notation

String

String is a very popular data type and they are used to represent text. We spend a lot of time manipulating strings in
pretty much any programming language.

We create strings using literal values enclosed in single or double quotation marks. These literal also support a few
special encodings for common characters like new line, tab, and the quotation marks themselves. This is similar to what
happens with strings in many other programming languages.

var name = 'Homer', lastName = "Simpson";


var host = 'Conan O\'Brien';
var path = 'c:\\temp\\dir\\myfile.txt';
var tabDelimited = "COL1\tCOL2\tCOL3\nVAL1\tVAL2\tVAL3";

Every value in JavaScript can be converted to a string by using the toString() method, like var s = myValue.toString();.

Native Types
In addition to the primitive data types we just saw, JavaScript also provides a few other data types, which are
implemented as objects.

Date

We can store date values using Date objects. The Date object stores the date and time information internally as the
number of milliseconds since January 1st 1970.

There aren't date literals in the language, so we have to explicitly create a Date object when we need one.

var rightNow = new Date(); // current date and time


var holiday = new Date(2008, 6, 4); // 4th of July, note the
// 0-based month number
var birth = Date.parse('7/4/2008'); // 4th of July, format varies with browser
// locale (avoid this)
There two important pitfalls in the above example: the month is a number from 0 to 11 when passed as a parameter and
the parse-able string formats vary by browser implementation and by user locale, so we'd better off just avoid parsing
altogether.

Array

How useful would be our programs if we couldn't organize the data in arrays or other collection structures? I guess not
very much.

Arrays are very powerful in JavaScript and they kind of blur the lines between arrays and custom objects.

The Array object can be instantiated with both a constructor call or using literals. The array indices are not necessarily
contiguous or numeric or even of the same data type.

var CITIES = new Array();


CITIES[0] = 'Albuquerque';
CITIES[9] = 'Tampa';
var TEAMS = [ 'Cubs', 'Yankees', 'Mariners' ];
var BANDS = [ ];
BANDS['rock'] = "Beatles, Rolling Stones, Pink Floyd";
BANDS['punk'] = "Sex Pistols, Ramones, Dead Kennedys";
BANDS[1992] = "Nirvana, Pearl Jam, Soundgarden, Metallica";

Object

The Object type serves as the base for all the objects in JavaScript, regardless of their data type or how they were
created.

The Object type is also used when we want to create custom objects. We can create new objects using a constructor call
or a literal. We will cover this is greater detail in a future lesson.

var employee = new Object();


employee.name = 'Homer Simpson';
employee.badgeNumber = 35739;
var boss = { }; //literal syntax, empty though
boss.name = 'Montgomery Burns';
boss.badgeNumber = 1;
employee.reportsTo = boss;

Regular Expressions

Regular Expressions is a syntax used to find occurrences of a string pattern inside a larger string. It has historically
been more popular in Unix environments and in Perl programs, but it has gained some adoption in many other
programming languages as well.

Regular expressions is one of these technologies with a measurable learning curve but that can have a big payoff
depending on the type of work you do.

JavaScript implements regular expressions with RegExp objects. It also support the Perl-syle literals.

var text = "Webucator";


var pattern = new RegExp('cat', 'g');
var samePattern = /cat/g; //using the literal syntax
alert( pattern.test( text ) );// shows 'true'

Functions
Functions in JavaScript are more than just static blocks of code. They are Function objects that we use just like any
other data type value, e.g. we can pass functions to other functions, we can store a function in a variable, we can
modify a function, etc.

We will have a lot to talk about functions in one of our lessons. For now let's just remember how we declare and call
functions.

//declare the function


function sayHowMuch(name, price, quantity) {
var finalPrice = price * quantity;
alert('The price for ' + quantity + ' ' +
name + '(s) is $' + finalPrice);
}

//call the function with arguments


sayHowMuch('ice cream cone', 1.99, 3);
sayHowMuch('Movie ticket', 10.00, 5);

The DOM is not JavaScript


A common source of confusion is the relationship between the browser DOM (Document Object Model) and the
JavaScript global objects.

JavaScript being an interpreted language with a runtime execution engine, it needs a host environment to instantiate the
engine and forward the JavaScript code to it. The browser is one of many hosts for JavaScript. Other hosts are Adobe
Flash plugins (via ActionScript), desktop widgets (like Yahoo! Widgets, MS Gadgets, OS X Dashboard Widgets),
Firefox browser add-ons, and even some kinds of electronic equipment.

All that said, the browser was the originally intended host for JavaScript and by far the most common one.

The DOM

It's important to understand that the DOM is a standard that has nothing to do with JavaScript. It was created by the
W3C to normalize the browser vendors' implementations of Dynamic HTML.

The DOM is an API that enables programatic access to the HTML document structure, for reading or modification
purposes. When we write code like document.getElementById('abc') we are using the DOM.

With the DOM we can traverse our entire HTML document looking for specific HTML elements, which are called
nodes, or even create new elements and append them pretty much anywhere we want inside the HTML document.

The window object

In browser scripts, the document object is actually a property of the window object, which is the default (or global)
object of JavaScript in that environment. So typing window.document.body is the same as typing document.body. The
DOM starts at the document object.

There are other things one may think are part of JavaScript when, in fact, they're browser-specific features, like the
alert(), prompt(), setTimeout(), and open() functions. These are just methods of the window object, not part of
JavaScript per se.

The XMLHttpRequest object


Another important object that we use a lot in JavaScript these days is the XMLHttpRequest object. This is the object
that powers the AJAX functionality in a lot of web pages.
This object is also not part of JavaScript. It can be used from JavaScript but it isn't part of the language.

We won't cover AJAX here but it suffices to understand that this object allows our scripts to initiate a request to an
URL and collect the server response without the need to reload the entire page.

function saveUser(name, age) {


//the following line is actually a grossly simplified version
// that is not supported in all browsers
var ajax = new XMLHttpRequest();

ajax.open('POST', '/users/update', true);


ajax.onreadystatechange = function () {
if (ajax.readyState == 4) {
alert('User ' + name + ' updated.');
}
};

ajax.send( 'userName=' + name + '?userAge=' + age );


}
saveUser('Joe Doe', 54);

Quick JavaScript Recap Conclusion


We hope that after this short tour of JavaScript data types and the browser execution environment you will be able to
absorb all the new concepts you are about to see in the remainder of the course.

Because of the syntax similarities with C-style languages, it's often possible that we mix-up what is available in
JavaScript so this lesson can serve as a quick reminder or cheat-sheet when needed.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Advanced Techniques
In this lesson of the JavaScript tutorial, you will learn...

1. To use the default operator.


2. To pass a flexible number of arguments to a function.
3. To pass a function as an argument to another function.
4. To create anonymous functions.
5. Other techniques related to functions.

Beyond The Basics


You can go very far in JavaScript using only the language basics that we have seen up to now but, to really unleash
JavaScript's power, we need to get more familiar with a few programming techniques.

These techniques will help your code become more expressive and more reusable at the same time. They are
programming patterns that leverage some language features that may not be present in other programming languages.

If you don't have experience with any other dynamically typed or functional language, the patterns you will see here
may look very strange at first. But fear not, we will provide plenty of explanations and examples to make you feel
comfortable enough to read and write JavaScript code that employ what you just learned.

Optional Function Arguments


When we declare a function in JavaScript, we normally include a list of the arguments the function expects.

Code Sample: AdvancedTechniques/Demos/sumAll-1.html


---- Code Omitted ----

function sumValues(val1, val2, val3) {


return val1 + val2 + val3;
}
---- Code Omitted ----

But this does not guarantee that our function will always be called with 3 arguments. It's perfectly valid for someone to
call our function passing more than 3 or even less than 3 arguments.

var R1 = sumValues(3, 5, 6, 2, 7);


var R2 = sumValues(12, 20);

Both calls will return surprising results (surprising from the caller's perspective.)

In the first case, since we are not expecting more than 3 arguments, the extra values, 2 and 7, will simply be ignored.
It's bad because the returned value is probably not what the calling code expected.

It's even worse when we look at the second example. We are passing only 2 arguments. What happens to val3? It will
have the value of undefined. This will cause the resulting sum to be NaN, which is clearly undesirable.

Let's fix our function to deal with these types of situations.


Code Sample: AdvancedTechniques/Demos/sumAll-2.html
---- Code Omitted ----

function sumValues(val1, val2, val3) {


if (val1 === undefined) {
val1 = 0;
}

if (val2 === undefined) {


val2 = 0;
}

if (val3 === undefined) {


val3 = 0;
}

return val1 + val2 + val3;


}

var R1 = sumValues(3, 5, 6, 2, 7);


var R2 = sumValues(12, 20);
---- Code Omitted ----

If we run our example again, we will see that we no longer get NaN for the second function call. Instead we get 32,
which is probably what the calling code expected.

We now have a pretty robust function that adds 3 numbers but it still doesn't feel all that useful. Sooner or later we will
need to add four or five numbers and we don't want to be updating our function to accept a val4 then a val5 parameters.
That would be a less than desirable maintenance task. Fortunately JavaScript can help us with that too.

Every function, when called, receives a hidden parameter called arguments, which is an array of all the arguments
passed to the function. Back to our example, the first time we call sumValues, the arguments array will contain [3, 5, 6,
2, 7] and in the second call [12, 20].

What this means is that we can ignore the passed parameters altogether an deal only with the arguments array. Let's
update our function once again.

Code Sample: AdvancedTechniques/Demos/sumAll-3.html


---- Code Omitted ----

function sumValues() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}

var R1 = sumValues(3, 5, 6, 2, 7);


var R2 = sumValues(12, 20);
---- Code Omitted ----

Note how we got rid of the parameter list and now we get the values directly from the arguments array. When we run
our example now we see that the returned values are correct and precisely what was expected by the caller. We now
have a function that accepts as many parameters as are thrown at it and will always return the sum of all those
arguments.

Truthy and Falsy


JavaScript, as we already know, has a boolean data type, which has only two possible values: true or false. Boolean
expressions also evaluate to a boolean value. But that's not the entire story.

When used in a context that expects a boolean value, any JavaScript expression can be used. See below.

var NUMBER = 0;
if (NUMBER) {
alert('You should not see this');
}
NUMBER = 1;
if (NUMBER) {
alert('You should be reading this');
}
var TEXT;
if (TEXT) {
alert('You should not see this');
}
TEXT = "";
if (TEXT) {
alert('You should not see this');
}
TEXT = "hi";
if (TEXT) {
alert('You should be reading this');
}

In the example above we are using non-boolean expressions (NUMBER and TEXT) in the if statement and some of
these expressions are being understood as true and some others false.

What is happening here is Type Coercion. JavaScript does its best to convert the given expression into the desired type
(boolean.)

JavaScript resolves the following values to false.

• false (of course)


• null
• undefined
• 0 (zero)
• NaN
• "" (empty string)

The above values are all referred to as falsy, which is a way of saying "Not the same as false but can be interpreted like
such."

Every other value, including the strings "0" and "false", will resolve to true and will be referred to as truthy. Again,
"Not the same as true but can be interpreted as such."

Type coercion is the reason we have the === (triple-equal or strictly equal) comparison operator in JavaScript. The
regular equality operator == applies type coercion and sometimes your comparisons will not result as expected. Look at
the following sample code.

var NUM = 0;
if (NUM == "") {
alert('Hey, I did not expect to see this.');
}
if (NUM === "") {
alert('This will not be displayed.');
}

In the first if conditional is comparing two falsy values, and the type coercion will resolve both of them to false,
causing the result of the comparison to be true, which is probably not the original intent of the code.
To detect the type difference (string vs. number) we would need to use the triple equal operator, as shown in the second
if statement.

Default Operator
The boolean operators && and || also use truthy and falsy to resolve each of the operands to a boolean value.

From your previous experiences with other programming languages you may be led to believe that the result of a
boolean operation is always true and false. This is not the case in JavaScript.

In JavaScript, the result of a boolean operation is the value of the operand that determined the result of the operation.
Let's clarify that with an example.

var A = 0, B = NaN, C = 1, D = "hi";


var RESULT = ( A || B || C || D );
alert("Result = " + RESULT);

RESULT = ( D && C && B && A );


alert("Result = " + RESULT);

The first boolean expression ( A || B || C || D ) is evaluated from left to right until a conclusion is made. The || is the
boolean OR operator, which only needs one of the operands to be true for the operation result in true. A is 0, which is
falsy. The evaluation continues with the remaining operands because falsy didn't determine anything yet. When
checking B, which is NaN and also falsy, we have the same situation - we need to continue evaluating. Then we check
C, which is 1 and resolves to true. We no longer need to continue evaluating the remaining operands because we
already know the expression will result true. But here's the catch. Instead of resulting strictly true, it will result in the
truthy value that ended the evaluation, C in our case. The message displayed will be "Result = 1".

As you might already expect, the && (boolean AND operator) works in a similar fashion, but with opposite conditions.
The AND operator returns false as soon as it finds an operand that is false. If for the expression ( D && C && B && A
) we follow the same sequence we did for the OR operator we will see that, D and C are both truthy so we need to keep
going, then we get to B, which is falsy and causes the evaluation to stop and return B. The message displayed then is
"Result = NaN".

You may be reading all this and thinking how can this be of any use. It turns out that this behavior of returning the first
conclusive value can be very handy when ensuring that a variable is initialized.

Let's take another look at a function we saw back in the Form Validation lesson.

function checkLength(text, min, max){


min = min || 1;
max = max || 10000;

if (text.length < min || text.length > max) {


return false;
}
return true;
}

The first two lines in this function make sure that min and max always have a valid value. This allow the function to be
called like checkValue("abc"). In this case the min and max parameters will both start with the undefined value.

When we reach the line min = min || 1; we are simply assigning 1 to min, ensuring it overrides the undefined. Similarly
we assign 1000 to max.

If we had passed actual values for these parameters as in checkLength("abc", 2, 10) these values would be kept because
they are truthy.

With this usage of the || we are effectively providing default values for these two parameters. That's why this operator,
in this context, is also called the Default Operator.
The default operator replaces more verbose code like:

if (min === undefined) {


min = 1;
}
// becomes simply
min = min || 1;

var contactInfo;
if (email) {
contactInfo = email;
} else if (phone) {
contactInfo = phone;
} else if (streetAddress) {
contactInfo = streetAddress;
}
// is greatly shortened to
var contactInfo = email || phone || streetAddress;

Exercise: Applying defaults to function parameters

Duration: 15 to 25 minutes.

Here we will revisit an earlier example and use the default operator to handle optional parameters.

1. Open AdvancedTechniques/Exercises/sumAll-defaults.html for editing.


2. Edit the existing sumAll() to use the default operator instead of the if blocks.

Code Sample: AdvancedTechniques/Exercises/sumAll-defaults.html


<html>
<head>
<title>Sum all numbers, default operator</title>
<style type="text/css">
.wc_debug
{
background-color:#ffc;
}
</style>
</head>

<body>
<h1>Sum all numbers, default operator</h1>
<script type="text/javascript" src="../../Libraries/DebugHelp.js" ></script>
<script type="text/javascript">
insertDebugPanel();

// this function uses the if blocks to


// handle the optional parameters.
// Change it to use the default operator instead.

function sumValues(val1, val2, val3) {


if (val1 === undefined) {
val1 = 0;
}

if (val2 === undefined) {


val2 = 0;
}

if (val3 === undefined) {


val3 = 0;
}

return val1 + val2 + val3;


}

var R1 = sumValues(3, 5, 6, 2, 7);


var R2 = sumValues(12, 20);

//print the results


debugWrite(R1);
debugWrite(R2);
</script>

</body>
</html>
Where is the solution?

Functions Passed as Arguments


In JavaScript functions are first class data types. Functions aren't just an immutable block of code that can only be
invoked. In JavaScript each function we declare becomes an object, with its own properties and methods, and can also
be passed around like any other object.

Let's see how we can use functions as parameters to other functions. Consider the following example.

Code Sample: AdvancedTechniques/Demos/function-arguments.html


---- Code Omitted ----

var VALUES = [5, 2, 11, -7, 1];

function sum(a, b) {
return a+b;
}

function multiply(a, b) {
return a*b;
}

function combineAll(list, initialValue, operation) {


var runningResult = initialValue;
for (var i=0; i< list.length; i++) {
runningResult = operation(runningResult, list[i]);
}
return runningResult;
}

var SUM = combineAll(VALUES, 0, sum);


var PRODUCT = combineAll(VALUES, 1, multiply);
---- Code Omitted ----

You may be wondering what the following function call means: var SUM = combineAll(VALUES, sum);. In this
statement we are passing the function sum as the second parameter of combineAll. We are not invoking sum yet, just
passing a reference to it. Note that the open and close parenthesis aren't used after sum, that should serve as a tip off
that this is not a function invocation.

The line that ultimately invokes sum is runningResult = operation(initialValue, list[i]);, which received a reference to
sum in the operation parameter. When operation is invoked, in reality, it is sum that is getting called, returning the sum
of the two values passed in.

This is a very important technique and the combineAll function is often called reduce. Take your time to review the
code and run the example until you feel comfortable with it. We will be using this capability extensively in the
remaining lessons.

Anonymous Functions
Going back to our previous example, the functions sum and multiply are only referred to once, in each call to
combineAll. Furthermore, if we stick to that pattern, any new combination behavior that we desire, such as concatenate
the values or compute the average value, will need a new function just to be passed to combineAll. That seems like too
much overhead for such a simple thing. It would also not be very interesting to have all these functions that do such
simple things scattered through out the code.
Thankfully, we don't actually need to declare each of these functions. We don't even need to come up with names for
them. JavaScript allow us to create functions on the spot, any time we need a function that will only be used at that
spot.

The syntax is rather compact.

Syntax
function (arg1, arg2) {
//function statements here
}

Because the functions created this way don't have names, they are aptly called anonymous functions.

Let's revisit our previous example and use anonymous functions to replace the single-use functions we declared.

Code Sample: AdvancedTechniques/Demos/anon-func-arguments.html


---- Code Omitted ----

var VALUES = [5, 2, 11, -7, 1];

function combineAll(list, initialValue, operation) {


var runningResult = initialValue;
for (var i=0; i< list.length; i++) {
runningResult = operation(runningResult, list[i]);
}
return runningResult;
}

var SUM = combineAll(VALUES, 0, function (a, b) {


return a+b;
});

var PRODUCT = combineAll(VALUES, 1, function (a, b) {


return a*b;
});
---- Code Omitted ----

The highlighted code represent the two anonymous functions, located where previously we had sum and multiply. This
coding style can understandably be harder to read, but it also avoids all that jumping around to look up what that
function that you are passing by name really does. The code of that function is right there, next to the code that is using
it.

Inner Functions
Since functions in JavaScript are just one more type of object, we can create a function inside another function. These
are called inner functions.

The example below shows how to create and use a function inside another one.

function analyzeText(text) {
var index = 0;

function getNextCharacter() {
if (index < index.legth) {
return text.charAt(index);
}
return false;
}

var c = getNextCharacter();
while (c) {
alert(index + ' ---> ' + c );
c = getNextCharacter();
}
}
analyzeText('abcdef');

The above example is not particularly useful. We will see more important uses of inner function when we look at
private members. For the time being, just notice how getNextCharacter() has access to index and text, which are scoped
to the analyzeText() function.

The eval() Function


The reason we are mentioning eval() in this lesson is to acknowledge its existence and to urge you not to use it. We will
explain why, but first let's explain what it does.

eval interprets a string containing JavaScript code. It can be a simple expression like "1 + 2" or a long and complex
script, with functions and all.

Here's one example that is not too different from what we can find in live sites on the web.

function getProperty(objectName, propertyName) {


var expression = objectName + "." + propertyName;
var propertyValue = eval(expression);
return propertyValue;
}
var PROP = "title"; //assume this was given by the user
alert(getProperty("document", PROP)); //shows the window title

This function creates a JavaScript expression by concatenating an object name, with a dot and a property name. Then it
uses eval to evaluate that expression.

As we can see eval is a powerful function, but it is also potentially dangerous and incredibly inefficient. It's dangerous
because it's typically used to evaluate user entered input, which not always is a safe thing to do. It's inefficient because
each call to eval starts a JavaScript compiler.

The use of eval normally reveals lack of knowledge from the developer that wrote the script. For example, the sample
that we just used is not necessary. Probably what happened was that the developer did not know about the [ ] accessor
for properties. The same effect would be obtained with alert(window[PROP]);, with the advantage of not firing up a
compiler just to retrieve the property value.

Remember this, eval is evil. Avoid it as much as you can. If you think you need it, maybe it's because you did not learn
yet about an alternative way in JavaScript.

Variable Scope
Variable scope defines which parts of your code have access to a variable that you define. This typically varies
depending where you declare the variable.

Variables in JavaScript are either global or function scoped. When a variable is declared outside of any function body,
then it will become a global variable, meaning that any portion of your script will have access to it.

var NAME = 'my global value';


function displayName() {
alert(NAME);
}
alert(NAME);
displayName();

The previous sample showed that the Name variable is visible inside the function displaName.
There's a catch, though. If you forget to declare the variable using the var operator before using the variable, the
variable will be created as a global variable even if you are declaring it inside a function or inside a for loop
declaration.

function prepare() {
TEST = 123;
alert(typeof TEST);
//let's forget the "var" in the "for" declaration
for (abc=0; abc<5; abc++) {
//...
}
}

alert(typeof TEST);
prepare();
alert(TEST);
alert(abc);

Function Scope

Variables declared with var inside a function will be visible only inside that function. It doesn't matter if the variable
was declared inside an if block or a for block. Once declared, the variable becomes visible throughout the remainder of
the function. What that means is that JavaScript doesn't have block scope.

Advanced Techniques Conclusion


Hopefully, with what you learned in this lesson you will be able to write much more robust JavaScript code and start
leveraging some of the flexibility JavaScript puts at your disposal to create really powerful code.

If you still feel unsure of how these techniques work, re-read the lesson and look for alternative explanations on the
web. Sometimes it helps reading a different phrasing of the same topic. It's important that you can at least read this type
of code fluently in order to understand some of what we will be looking at in the upcoming lessons.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Object Oriented Aspects of JavaScript
In this lesson of the JavaScript tutorial, you will learn...

1. That JavaScript is, in fact, object oriented.


2. To create new objects in a variety of ways.
3. To be careful with the this keyword.
4. The difference between call() and apply().
5. To extend existing objects.

Yes, JavaScript is Object Oriented


If you are a web developer, chances are you work with an object oriented language on the server side, be it Java, C#,
Ruby, VB, etc. You may also already understand the advantages of using an OO programing language over a purely
procedural one.

In this lesson and the next one we will provide quick recipes of how common OO techniques are implemented with
JavaScript. We will also present some additional techniques that may not be available in other OO languages that you
are familiar with.

In this lesson we will cover most of the OO concepts as implemented in JavaScript. The screaming exception is
Inheritance, which we we will defer to the next lesson.

Why Create JavaScript Objects?


Let's get back to our server code once again. If you are writing an application that reports data from a database, you are
probably dealing with objects such as database connections, recordsets, error loggers, etc. You may also have custom
objects that represent entities from your problem domain, like Order, Employee, Company, PriceQuote, etc.

You need those objects because they encapsulate a lot of functionality that we can reuse over and over. It should not be
surprising that soaring demand for Rich Internet Applications (RIA), the need for objects to assist with the UI logic also
increases.

What we are suggesting here is that it is much more appropriate to produce reusable JavaScript objects than vast
collections of JavaScript functions. The problem with the functions, as we know from procedural programming
languages, is that they are either too complex to use (because they want to solve all the possible variants of the
problem) or they need to be called in a specific sequence.

Imagine that you have the common scenario of cascading drop down lists, one with a list of countries, the other with
states or provinces. When the country changes you want to update the states list accordingly.

If we were doing this in a procedural fashion, we would create a function to handle the change event of the countries
list, in this function we would call another function, passing the country name to refresh the states list. This second
function would receive the country name, retrieve the states list and update the states drop down.

Code Sample: ObjectOrientedJS/Demos/cascading-original.html


---- Code Omitted ----

function countryChanged() {
var sel = document.getElementById("country");
var country = sel.options[sel.selectedIndex].value;
updateStateList(country);
}
function updateStateList(country) {
var states = STATES_PER_COUNTRY[ country ];
var list = document.getElementById("state");
list.options.length = 0;
for (var i=0; i<states.length; i++) {
list.options.add( new Option(states[i]) );
}
}

document.getElementById("country").onchange = countryChanged;
---- Code Omitted ----

A few days later we may need to implement a similar scheme, but this time with a Company/Employee pair of drop
downs. Here we go writing all that code again.

If we were using an OO approach, we could create an object called CascadingListPair that knows how to capture the
change events of the first drop down, call some code to retrieve the list for the second drop down, and update the
second dropdown.

Code Sample: ObjectOrientedJS/Demos/cascading-objects.html


---- Code Omitted ----

var helper = new CascadingListPair(


"country",
"state",
function (country) {
return STATES_PER_COUNTRY[ country ];
});

---- Code Omitted ----

Don't worry about how complex the above code looks right now. We will discuss what is going on during this lesson.
For now just appreciate how much shorter this is and how much logic you did not have to write.

Now if we were to create a cascading pair for Company/Employee, it would be so much simpler.

var helper2 = new CascadingListPair(


"company",
"employee",
function (company) {
return EMPLOYEES_PER_COMPANY[ company ];
});

Creating Simple Objects


Objects are the fundamental unit of code encapsulation and reuse in any OO language. It is incredibly easy to create
objects in JavaScript. There's even more than one way to do so.

1 - Building objects

The first approach is to create an empty object and progressively add its properties and methods.

Code Sample: ObjectOrientedJS/Demos/building-objects.html


---- Code Omitted ----

var GUITAR = { };
GUITAR.color = 'black';
GUITAR.strings = ['E', 'A', 'D', 'G', 'B', 'e'];
GUITAR.tune = function (newStrings) {
this.strings = newStrings;
};
GUITAR.play = function (chord) {
alert('Playing chord: ' + chord);
};
GUITAR.print = function (price, currency) {
alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
};
//using the object
GUITAR.play('Dm7');
GUITAR.tune( ['D', 'A', 'D', 'G', 'B', 'e' ] );
debugWrite('this guitar is: ' + GUITAR.color);
GUITAR.print(850, 'USD');

---- Code Omitted ----

The above methodology isn't too hard to understand but it is certainly more work than we are used to in more popular
programming languages. What we did here is quite simple. We just created the object and appended each property and
method as desired.

2 - Declaring objects

JavaScript also has a literal notation for objects. The previous example could have been rewritten in literal notation as
follows.

Code Sample: ObjectOrientedJS/Demos/declaring-objects.html


---- Code Omitted ----

var GUITAR = {
color: 'black',

strings: ['E', 'A', 'D', 'G', 'B', 'e'],

tune: function (newStrings) {


this.strings = newStrings;
},

play: function (chord) {


alert('Playing chord: ' + chord);
},
print: function (price, currency) {
alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
}
};

//using the object


GUITAR.play('Dm7');
GUITAR.tune( ['D', 'A', 'D', 'G', 'B', 'e' ] );
debugWrite('this guitar is: ' + GUITAR.color);
GUITAR.print(850, 'USD');

---- Code Omitted ----

The syntax is easy to understand. It is a comma-delimited list of name: value pairs. Note that the method declaration is
easy to be confused with a regular function declaration. Just remember that a function can be used as a value and that's
what is happening here. You can also think of the methods as properties that contain a function as their values, if that
helps you understand the notation.

JSON
JavaScript Object Notation, or JSON, is a subset of the literal notation that we just saw. JSON was first proposed by
Douglas Crockford as a neutral way to represent and transport data, usually replacing XML.

JSON, just like the literal notation, is also a list of name/value pairs. The main difference is that the values can only be
a string, an Array, a Number, true, false, null, or another JSON object. The field names are also enclosed in double-
quotes.

Here's the GUITAR object represented in JSON. Note that we cannot represent the methods because JSON doesn't
accept them. It makes sense because JSON is meant only for data interchange, where behaviors are irrelevant.

var GUITAR = {
"color":"black",
"strings":['E', 'A', 'D', 'G', 'B', 'e']
};

3 - Using factory functions

One important thing to notice in the previous two approaches is that we did not need to create a formal class to serve as
the template of the GUITAR object. If we needed a second guitar object we would need to create it the same way we
did for the first one.

We could just encapsulate that logic in a function that can create a brand new guitar object on demand.

Code Sample: ObjectOrientedJS/Demos/factory-functions.html


---- Code Omitted ----

function createGuitar(color, strings) {


var guitar = { };
guitar.color = color;
guitar.strings = strings;
guitar.tune = function (newStrings) {
this.strings = newStrings;
};
guitar.play = function (chord) {
alert('Playing chord: ' + chord);
};
guitar.print = function (price, currency) {
alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
};
return guitar;
}

var GUITAR1 = createGuitar('black', ['E', 'A', 'D', 'G', 'B', 'e'] );


var GUITAR2 = createGuitar('maple', ['F', 'Bb', 'D#', 'G#', 'C', 'f'] );

---- Code Omitted ----

4 - Constructors

There's a variation of the factory function methodology that may feel more natural to you. In JavaScript, when function
is called preceded by the new operator, the function receives an implicit this argument that is a brand new object, ready
to be assembled with properties and methods. Also, if we do not return anything explicitly, the new operator
automatically returns this.

Let's rework our last example into a constructor. A good convention is to start constructor functions with a capital
letter, to differentiate from a regular function, signaling to the programmer that it needs to be called with the new
operator.

Code Sample: ObjectOrientedJS/Demos/constructors.html


---- Code Omitted ----

function Guitar(color, strings) {


this.color = color;
this.strings = strings;
this.tune = function (newStrings) {
this.strings = newStrings;
};
this.play = function (chord) {
alert('Playing chord: ' + chord);
};
this.print = function (price, currency) {
alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
};
}

var GUITAR = new Guitar('black', ['E', 'A', 'D', 'G', 'B', 'e']);
debugWrite('this guitar is: ' + GUITAR.color);
GUITAR.play('Dm7');
GUITAR.tune( ['D', 'A', 'D', 'G', 'B', 'e' ] );
GUITAR.print(850, 'USD');

---- Code Omitted ----

The biggest differences here are two. First we no longer need to create the new object because the new operator has
already taken care of that and passed the new object under the this identifier. The other difference is that we will use
this wherever we were using guitar before. We could have returned this but that, as we explained above, is no longer
necessary.

Exercise: Creating objects to encapsulate behaviors

Duration: 30 to 60 minutes.

In this exercise we will implement the ever popular Yellow Fade Technique, where we set the background color of an
element to yellow and use timeouts to progressively fade the background back to white.

The exercise starts with working code that is not object oriented and has some problems because of that. We will
convert the existing code into an object type that has the same functionality and fixes the original shortcomings.

1. Open ObjectOrientedJS/Exercises/yellow-fade.html for editing.


2. Change the JavaScript code to get rid of the functions highLightElement(), increaseYellow(), and
setYellowLevel(), moving all that functionality into a constructor function called HighLightEffect().

Code Sample: ObjectOrientedJS/Exercises/yellow-fade.html


<html>
<head>
<title>Yellow Fade</title>
<style type="text/css">
.wc_debug
{
background-color:#ffc;
}
</style>
<script type="text/javascript" src="../../Libraries/DebugHelp.js" ></script>
</head>

<body>
<h1>Yellow Fade</h1>
<p>
Add items by name to your shopping cart.
</p>
<h2>Shopping cart</h2>
<table id="shoppingCart">
<tr><th>Item</th><th>price</th><th></th></tr>
<tr id="newItemRow" style="background-color:#ddd;">
<td colspan="3"><b>New item:</b></td>
</tr>
<tr>
<td><input type="text" id="itemName" /></td>
<td><input type="text" id="itemPrice" size="5" /></td>
<td><input type="button" id="addItem" value="Add" onclick="addingItem();" /></td>
</tr>
</table>

<script type="text/javascript">
function addingItem() {
var name = document.getElementById('itemName').value;
var price = document.getElementById('itemPrice').value;
var newItemRow = document.getElementById('newItemRow');
var table = document.getElementById('shoppingCart');
var shoppingCart = table.getElementsByTagName("tbody")[0];
var row = document.createElement('tr');

addCellToRow(row, name);
addCellToRow(row, price);
var buttonCell = addCellToRow(row, '');
var button = document.createElement('input');
button.type = 'button';
button.value = 'remove';
button.onclick = removingItem;
buttonCell.appendChild(button);

shoppingCart.insertBefore(row, newItemRow);

highLightElement(row);

function addCellToRow(row, cellText) {


var cell = document.createElement('TD');

cell.innerHTML = cellText;
row.appendChild(cell);
return cell;
}

function removingItem() {
//'this' it the remove button
var row = this.parentNode.parentNode;
row.parentNode.removeChild(row);
}

/*
All the above code can stay. The only thing we are
interested in this exercise is to replace the
functions below this comment with an object that
does the same thing.
Instead of doing this in addingItem():
highLightElement( row );
we want to write:
new HighLightEffect( row )
challenge:
-- Add extra properties and constructor parameters
to the object to control the duration of the effect
challenge 2:
-- Add more properties to configure the start and end color of the effect

*/

var LEVEL = 128;


var ELEMENT = null;
var INTERVAL = 100;

function highLightElement(element) {
ELEMENT = element;
LEVEL = 128;
setYellowLevel(element, LEVEL);
setTimeout(increaseYellow, INTERVAL);
}

function increaseYellow() {
LEVEL += 10;
if (LEVEL > 255) {
LEVEL = 255;
}
setYellowLevel(ELEMENT, LEVEL);
if (LEVEL < 255) {
setTimeout(increaseYellow, INTERVAL);
}
}

function setYellowLevel(element, level) {


var hex = level.toString(16);
element.style.backgroundColor = '#ffff' + hex;
}

</script>

<script type="text/javascript">
insertDebugPanel();
</script>

</body>
</html>

1. Change the HighLightEffect() function to take an extra parameter to configure the length of the effect in
seconds.
2. Make the new parameter optional with a default value of 1 second.
3. Change the example to pass in 2 seconds when creating the object.

1. Change the HighLightEffect() function to take another two extra parameters to configure start and end colors
of the effect.
2. Create a method that splits the RGB color components in a 3-element array with integer values.
3. In each timeout step, calculate the next value for each RGB component of the background color and set it.
4. Make these two extra parameters optional and default them to "#ffff99" and "#ffffff" respectively.
5. Change the background color of the shopping cart table to "#80ffff" and change the sample to use the start
color of "#cc99cc" and end color the same as this new background.

Where is the solution?

Memory usage

One thing is common in all the presented ways to create an object may go unnoticed. The play() and tune() methods
being added to each objects are always recreated from scratch for each object instance.

This will result in multiple copies of identical methods, which is clearly waste of memory. It may be a negligible waste
for those tiny methods and in just a couple of object instances, but it's generally not a good practice.

We will present the most adequate solution in the next lesson, but there's a middle-of-the-road alternative that we can
use to address the duplication issue in the meantime.

The idea is to create a single function for each of those methods and use them in the creation of the instance methods.
The example below illustrates this.

Code Sample: ObjectOrientedJS/Demos/reusing-functions.html


---- Code Omitted ----

function tuneGuitar(newStrings) {
this.strings = newStrings;
}

function playGuitar(chord) {
alert('Playing chord: ' + chord);
}

function printInfo(price, currency) {


alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
}

function Guitar(color, strings) {


this.color = color;
this.strings = strings;
this.tune = tuneGuitar;
this.play = playGuitar;
this.print = printInfo;
}

var GUITAR = new Guitar('black', ['E', 'A', 'D', 'G', 'B', 'e'] );

---- Code Omitted ----

This reduces the number of identical functions created but it has a different cost. The code now looks more dispersed.
The functions defined outside of the constructor method don't give any hint that they are used as methods of the Guitar
objects.

Although the object instantiation via constructors may look as if we are defining classes, we will learn in the next
lesson that this is not really true.

The perils of this


You may look at the previous example and wonder: What if someone calls tuneGuitar() directly, instead of through a
Guitar object? Or what happens if the Guitar constructor is called without the new operator? Well, that is trouble
indeed.

I JavaScript, most of the times, the this contains the object that owns the current method. One big exception are the
constructor functions as we just saw. When we call a function directly like tuneGuitar( someArray ); there's no owning
object for the stand alone tuneGuitar() function so this will be uninitialized. Or will it?

As it turns out, there is a default value for this, which is a global object. That object holds all our global variables as its
properties and global functions as its methods. When we are running JavaScript in a browser this global object is the
window object.

Back to our problem, if we call tuneGuitar() directly, we will end up adding a strings property to the window object,
which is the same as creating a global variable called strings.

Even worse is when we call a constructor without the new operator. In this case we will create a series of global
variables and functions. Another problem is that the variable that we are trying to assign the new object to will remain
undefined:

var GUITAR1 = Guitar('black', ['E', 'A', 'D', 'G', 'B', 'e']);


debugWrite(GUITAR1);
// => undefined

The bottom line here is that we have to make sure that when we a function has a this identifier then that function is
always called as an object's method or that we are providing the value for this explicitly, as we will see now.

Calling or Applying functions


In JavaScript functions are 1st class objects of type Function. As such they have properties and methods of their own.
Two of the methods are apply() and call().

We can use apply() and call() to invoke the function as if they were methods of whatever object we want. This is done
by effectively setting the desired value of this.

Back once again to our Guitar objects and this time the printInfo() function.
function printInfo(price, currency) {
alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
}

We already know that if we call this function directly, it will cause problems because this will be the window object.
Since window doesn't have a strings property, the expression this.strings.length will fail.

Here's how we can overcome this problem.

var GUITAR1 = new Guitar('black', ['E', 'A', 'D', 'G', 'B', 'e']);
printInfo.call( GUITAR1, '349.99', 'USD');
// OR
printInfo.apply( GUITAR1, ['349.99', 'USD']);

Both apply() and call() will produce the same result. The only difference is how the parameters are passed to the
invoked function. apply() just expects all the parameters listed right after the target object. call() expects that the second
parameter will be an array of the parameters to be passed to the function.

This difference can become useful when dealing with an unknown (or flexible) number of arguments.

Code Sample: ObjectOrientedJS/Demos/call-apply.html


---- Code Omitted ----

var UTILS = {
getMaxLength: function () {
var max = 0;
for (var i=0; i<arguments.length; i++) {
if (arguments[i].length > max) {
max = arguments[i].length;
}
}
return max;
},

pad: function (text, maxLength) {


var result = text;
for (var i=text.length; i<maxLength; i++) {
result = ' ' + result;
}
return result;
},

alignRight: function () {
var maxLength = this.getMaxLength.apply(this, arguments);
var result = [];
for (var i=0; i<arguments.length; i++) {
result.push( this.pad(arguments[i], maxLength) );
}
return result;
}
};

var ALIGNED = UTILS.alignRight('Homer', 'Leonard', 'Montgomery', 'Abe');

---- Code Omitted ----

Extending Existing Objects


When we showed how to create objects by building them, one thing that we did not mention but may go unnoticed is
that we can add properties and methods to any object. It does not matter if the object was created by us or not.

To illustrate this, let's find a DOM element in a page, which is clearly an object not created by us, and let's extend it by
adding new members.
Code Sample: ObjectOrientedJS/Demos/extending-objects.html
---- Code Omitted ----
<div>
<div id='userName'>Joe Doe</div>
<input type="button" value="Prepare" onclick="extend('userName', '#ffff99');" />
<input type="button" value="Highlight" onclick="show('userName');" />
</div>

<script type="text/javascript">

function extend(elementName, color) {


var el = document.getElementById(elementName);
el.highlightColor = color;
el.highlight = function () {
this.style.backgroundColor = this.highlightColor;
};
}

function show(elementName) {
var el = document.getElementById(elementName);
el.highlight();
}
</script>
---- Code Omitted ----

In this example the first button calls extend() to extend the userName div element. To extend the element, it tries to find
the element in the document, if the element is found then a new property called highlightColor is added with the chosen
color value. A new method is then added with the name highlight, which will simply set the element's background color
style to the value contained in highlightColor.

The second button calls show(), which will once again find the element and call the brand new method highlight(). This
causes the userName element to display a yellow background.

This type of object modification is an important characteristic of Dynamically Typed programming languages like
JavaScript.

Merging Objects
The technique of adding new members to an existing object is so common in JavaScript libraries that some of them
formalize and encapsulate this operation.

The code below is from the Prototype.js library and show the Object object itself being extended with a function that
helps extending any object.

Object.extend = function(destination, source) {


for (var property in source)
destination[property] = source[property];
return destination;
};

With this new method we can make the process of augmenting an existing object look more like we are merging it with
a second one. Prototype.js uses this method many times in its own source code as shown below.

Object.extend(String.prototype, {
escapeHTML: function() {
return this.replace(/&/g,'&amp;').
replace(/</g,'&lt;').
replace(/>/g,'&gt;');
},
unescapeHTML: function() {
return this.replace(/&amp;/g,'&').
replace(/&lt;/g,'<').
replace(/&gt;/g,'>');
}
});
Dynamic Languages
A dynamic language is one where the type of the objects is only loosely bound to the way it was created. Objects may
be created through a constructor method and inherit from a base class or a prototype but that doesn't mean that the
object is locked for alterations.

Code can, at any time, add, remove or modify existing properties or methods of the objects. For that reason the base
type of an object is less important in a dynamic language than it is in a statically typed language like Java or C#.

Duck Typing

A famous sentence reflects very well the importance given to base types in dynamic languages: "If it walks like a duck
and quacks like a duck, I would call it a duck."

The gist of this statement is that in order for your code to work with a given object, you don't need the object to derive
from a particular base type or prototype. You only need it to honor the expected public interface. As an example, as
long as the given object has a method called sort(), your code will be able to call that method to sort the contents of the
object. It doesn't matter if the object is an array or a DOM tree or a custom hash-like object.

That sounds Dangerous

You may think that dynamic typing is a recipe for disaster but in practice that's not the case. There are two important
factors that make dynamic languages very appealing.

Productivity

How many times when programming in statically typed languages we were in the situation where we had this class that
was almost perfect but it lacked one important property or method? The usual route is to inherit a new class from that
one and add the missing functionality.

That works well in the beginning but it quickly leads to class explosion in the application. Before you notice you'll have
dozens of classes that are minor improvements over other existing classes.

Dynamic languages offer the capability of "fixing" the original classes on the spot and keep the code-base smaller and
more manageable. That leads to greater programmer efficiency.

Unit Testing

Dynamic languages walk hand-in-hand with unit testing. We will take a closer look at unit testing in the next lesson but
let's just say that automated unit testing will help detecting a bug at the moment it is introduced in the code.

I wouldn't try tell you that unit testing is very popular in JavaScript, but in other dynamic languages like Ruby and
Python it's common practice in enterprise-quality software. JavaScript is in a way still discovering the importance of
unit testing.

Private members
Up to now all the properties and methods that we have been adding to our objects are accessible from any code that
interacts with the object. In other object oriented programming languages it's often possible to define some of the
properties and methods as private to the object itself. This private members are only accessible by code in the object
itself but not from code that simply uses the object.
JavaScript, at the current version, does not support private members as a language feature. But not all is lost. With a
clever little trick we can create objects with private members.

Code Sample: ObjectOrientedJS/Demos/private-members.html


---- Code Omitted ----

var Cycler = function () {


this.values = arguments;

//private members
var current = 0;
var itemCount = arguments.length;
var that = this;

var moveIndex = function () {


current = (current + 1) % itemCount;
}

//public members
this.next = function () {
moveIndex();
return that.values[current];
};
};

var WEEKDAYS = new Cycler('Mon', 'Tue', 'Wed', 'Thu', 'Fri');

---- Code Omitted ----

The trick is related to JavaScript's variable scoping rules. Local variables inside the constructor function are visible
inside the constructor, including in the functions defined inside the constructor, like moveIndex() and next(). Even
moveIndex() is declared as a local variable.

Object Oriented Aspects of JavaScript Conclusion


In this lesson we started to see how JavaScript implements basic object creation. We also saw how flexible JavaScript
is that we can even modify existing objects not created by us. We're only scratching the surface on the dynamism
provided by this language.

In the next lesson we will explore JavaScript objects even further, when we explain how inheritance is implemented
using protype objects.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Prototype-Based Programming
In this lesson of the JavaScript tutorial, you will learn...

1. The differences between class-based and prototype-based programming


2. To construct objects from other objects
3. How JavaScript accomplishes inheritance
4. To define constructor functions
5. How JavaScript resolves object members
6. The prototype object

Software developers that work with Object Oriented programming languages are familiar with the concept of classes.
As it turns out, that's common but it's not the only way to accomplish object orientation and the JavaScript language
designers chose not to use the most common one.

In this lesson we will understand how JavaScript implements inheritance and how we can use it to build rich object
hierarchies.

Class-Based Programming
If you have previous experience with Object Oriented languages such as Java, C++, C# or Visual Basic, chances are
that you have employed class-based inheritance. You may have even concluded that was the only way to write object
oriented software.

In class-based inheritance, there's a clear distinction between the classes (or class objects) and the instances (or instance
objects.) The classes define the behavior and structure of instance objects, which in turn simply contain instance data.

The examples below illustrate a class being defined and then used in two different class-based programming languages.

//java or C#
class Door{
public void open(){
//...code omitted
}
}
Door frontDoor = new Door();
frontDoor.open();

'Visual Basic
Class Door
Public Sub Open()
'...code omitted
End Sub
End Class

Dim frontDoor as new Door()


frontDoor.Open()

Another important characteristic of class-based programs is how inheritance is implemented. Each class that you create
has a base class (or super class) explicitly or implicitly defined. Members of the base class will become available to the
new class (the derived or inherited class.)

Let's expand our examples a little bit to show class inheritance.

//java
class SafeDoor extends Door{
public void unlock(string secretCombination){
//...code omitted
}
}
SafeDoor safe = new SafeDoor();
safe.unlock("4-8-15-16-23-42");
safe.open();

'Visual Basic
Class SafeDoor
Inherits Door
Public Sub UnLock(ByVal secretCombination As String)
'...code omitted
End Sub
End Class

Dim safe as new SafeDoor()


safe.UnLock("4-8-15-16-23-42")
safe.Open()

Prototype Based Programming


Some languages choose to offer object oriented programming through mechanisms other than classes. One such
mechanism is prototyping. JavaScript, Self, Lua, ActionScript, Agora, Cecil and many other languages are prototype-
based.

Prototyping

Prototyping is a way to create objects by replicating another object (the so called prototype.) The new object may or
may not have a link to the original object, depending on the language implementation. JavaScript maintains a link
between the two as we will see shortly.

In prototype-based languages there's usually an operator to effect the object creation by copying another object.
Surprisingly JavaScript does not offer such operator, which is often consider a design flaw of the language.

What we are looking for in such operator is a way to write the following code.

Syntax
//attention, this is invalid syntax
var BRAND_NEW_OBJ = object( EXISTING_OBJ );

Unfortunately, the object function above does not come with JavaScript. On the other hand, nothing stops us from
creating our own implementation of that operator.

function object(original) {
function F() {}
F.prototype = original;
return new F();
};

We will defer the explanation of the above function for a little later, after we explain some of the language features
used in this code.

Prototypal Inheritance
Let's now take a look at prototypes in action and create an object hierarchy. Hopefully this will clarify how prototype
objects relate to the new objects that derive from them.

Consider the following simple implementation of an vehicle object.

var vehicle = {
wheels: 0,
color: 'white',
make: 'ACME',
model: 'Unknown',
year: 1998
};

This will produce an object that we will illustrate in the following diagram. In the diagram the box represents the object
and each property/value stored in the object pair is listed.

We can easily derive a more specialized car from the vehicle object with the help of the object function we mentioned
above.

var car = object(vehicle);


car.doors = 2;

The above code first creates the car object by linking to the existing vehicle object that is given to the object function.
This link is represented by the arrow in the diagram below. After creating the car object, we add a new property called
doors with the value of 2.

Note in the above diagram that car does not have a copy of all the properties from vehicle. Only the new doors property
is stored in car. Will this work? Let's try it.

<html>
<head>
<title>Prototype-based inheritance</title>
<script type="text/javascript">
function object(original) {
function F() {}
F.prototype = original;
return new F();
};

var vehicle = {
wheels: 0,
color: 'white',
make: 'ACME',
model: 'Unknown',
year: 1998
};

var car = object(vehicle);


car.doors = 2;
</script>
</head>
<body>
The vehicle color is
<script type="text/javascript">document.write(vehicle.color)</script>
<br />
The vehicle has
<script type="text/javascript">document.write(vehicle.wheels)</script> wheels
<br />
The car has
<script type="text/javascript">document.write(car.doors)</script> doors
<br />
The car color is
<script type="text/javascript">document.write(car.color)</script>
<br />
</body>
</html>

When we load this example we see that it all works as intended, but how exactly this all worked?

The first three properties that we print are not hard to understand. They are standard properties just like we have seen in
previous lessons. The interesting line is the one that prints car.color. We did not explicitly add a color property to the
car object, so when JavaScript interpreter executes and tries to find that property in car it won't. But the interpreter
doesn't stop there. It will check if the object has a link to the object that was used during the creation process (the
prototype object.) In our case car does have a prototype so the interpreter proceeds to that object, vehicle, and tries to
find a member named color there. It will then find the property and print white.

The important thing to keep in mind here is that JavaScript knows about that arrow that we have in our diagram, and
follows that arrow when something is not found in the object at hand. If the prototype object at the end of said arrow
does not have the desired member, JavaScript will check if the prototype object has a prototype of its own and continue
to do that recursively until the member is found or no more prototypes are available, in which case an error will be
reported.

Overriding Properties

After closer inspection, we realize that our car has zero in its wheels property, which we don't agree with and want to
change to 4. We decide to change our car creation a little bit.

var car = object(vehicle);


car.doors = 2;
car.wheels = 4;

Then we add one extra output to our example.

The car has


<script type="text/javascript">document.write(car.wheels)</script>wheels
<br />

This causes our diagram to change slightly, showing a new wheels property in the car object.

When we execute the updated example, we can see that indeed our car is listed with 4 wheels. This happens because, as
we explained a few paragraphs before, the JavaScript interpreter only inspects the object's prototype when the desired
member is not found in the object itself. This mechanism allows us to override the prototype's members. The prototype
remains unchanged, we're just not reading the value from it anymore.

Constructor functions and prototypes


In the previous lesson we showed how we can use functions as object constructors. Because we did not talk about
prototypes back there, we could not tell the entire truth.

Every function has a prototype property that gets automatically assigned to the new object's (the one identified by this)
prototype. By default the function prototype will be Object.prototype but we can change that.

Let's rewrite one of the examples in the last lesson using a constructor function and its prototype.

//remember that we follow the convention


// to start constructor functions with a capital letter
function Guitar(color, strings) {
this.color = color;
this.strings = strings;
}

Guitar.prototype.tune = function (newStrings) {


this.strings = newStrings;
};

Guitar.prototype.play = function (chord) {


alert('Playing chord: ' + chord);
};

Guitar.prototype.print = function (price, currency) {


alert('This guitar is ' +
this.color +
', it has ' + this.strings.length + ' strings' +
' and it costs ' + price + currency);
};

Now the Guitar objects will have a prototype property that no longer points to the default Object.prototype. Instead, it
will point to Guitar.prototype and automatically inherit all the methods we just added to it.

Altering the prototype


The link between the object and its prototype is a live one. If we decide to alter the prototype values, the objects that
inherited from that prototype automatically gain access to the prototype modifications.

In the following example we will use the above Guitar constructor to create an object. After that we will add a new
method to Guitar.prototype and we will see that the previously created object will have immediate access to this new
method.

var GUITAR = new Guitar('Teak', ['E', 'A', 'D', 'G']);


GUITAR.play('F#'); //shows 'Playing chord: F#'
//augment the prototype
Guitar.prototype.repeatChord = function (chord, times) {
for (var i = 0; i < times; i++) {
this.play(chord);
}
};
//try it out
GUITAR.repeatChord('Em7', 3);
//shows 'Playing chord: Em7' three times

Extending Standard JavaScript objects


Similarly to our custom objects, the standard objects in JavaScript also have prototypes. For example, every string
inherits from String.prototype and every array inherits from Array.prototype.

To demonstrate what we can do with this knowledge, let's add a trim() method to all our strings.

Code Sample: Prototype-Based-Inheritance/Demos/string-trim.html


---- Code Omitted ----

debugWrite(typeof String.prototype.trim); // shows 'undefined'


String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
debugWrite(typeof String.prototype.trim); // shows 'function'
var TEXT = ' extra padded text ';
debugWrite('[' + TEXT.trim() + ']');//shows '[extra padded text]'

---- Code Omitted ----

Augmenting the prototypes of the native objects is a very powerful technique, taken to great lengths by popular
libraries like Prototype.js, which we are about to discuss.

Prototype-Based Programming Conclusion


As we can see, JavaScript bears only trivial syntax similarities with many of the other mainstream programming
languages. Under the surface, though, JavaScript is fundamentally different and many of the most important JavaScript
idioms are arguably less intuitive.
The important take away is that, although not as cleanly as in other languages, we can still write very solid OO code in
JavaScript. That, combined with the great flexibility of the language, make it a surprisingly viable programming
platform.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript Tutorial's Table
of Contents.
Error Handling and Debugging
In this lesson of the JavaScript tutorial, you will learn...

1. That errors can be trapped and dealt with


2. To use Firebug to trace and resolve errors

No matter how careful you are, it always seems that errors find their way into your code. Sometimes they
are runtime errors caused by unpredicted scenarios. Sometimes the errors are just incorrect behavior of
your code, popularly known as bugs.

Fortunately, we have tools to deal with either type of problem. In this lesson we will talk about detecting
and handling errors and also about tracing down bugs and take them out of our applications.

Runtime Errors
Web browsers are such an hostile environment that it is almost guaranteed that we will constantly deal with
runtime errors. Users provide invalid input in ways you didn't think of. New browser versions change their
behavior. An AJAX call fails for a number of reasons.

Many times we can't prevent runtime errors from happening, but at least we can deal with them in a manner
that makes the user experience less traumatic.

Completely unhandled errors


Look at this seemingly trivial code snippet.

function getInput() {
var name = window.prompt('Type your name', '');
alert('Your name has ' + name.length + ' letters.');
}

It may not be obvious, but this code has a bug waiting to break free. If the user clicks Cancel or presses Esc
the prompt() function will return null, which will cause the next line to fail with a null reference error.

If you as a programmer don't take any step to deal with this error, it will simply be delivered directly to the
end user, in the form of a utterly useless browser error message like the one below.

Depending on the user's browser or settings, the error message may be suppressed and only an
inconspicuous icon shows up in the status bar. This can be worse than the error message, leaving the users
thinking the application is unresponsive.

Globally handled errors


The window object has an event called onerror that is invoked whenever there's an unhandled error on the
page.

window.onerror = function (message, url, lineNo) {


alert(
'Error: ' + message +
'\n Url: ' + url +
'\n Line Number: ' + lineNo);
return true;
}

As you can see, the event will pass 3 arguments to the invoked function. The first one is the actual error
message. The second one is the URL of the file containing the error (useful if the error is in an external .js
file.) The last argument is the line number in that file where the error happened.

Returning true tells the browser that you have taken care of the problem. If you return false instead, the
browser will proceed to treat the error as unhandled, showing the error message and the status bar icon.

Here's the message box that we will be showing to the user.

Structured Error Handling


The best way to deal with errors is to detect them the closest possible to where they happen. This will
increase the chances that we know what to do with the error. To that effect JavaScript implements
structured error handling, via the try...catch...finally block, also present in many other languages.

Syntax
try {
statements;
} catch (error) {
statements;
} finally {
statements;
}

The idea is simple. If anything goes wrong in the statements that are inside the try block's statements then
the statements in the catch block will be executed and the error will be passed in the error variable. The
finally block is optional and, if present, is always executed last, regardless if there was an error caught or
not.

Let's fix our example to catch that error.

function getInput(){
try {
var name = window.prompt('Type your name', '');
alert('Your name has ' + name.length + ' letters.');
} catch (error) {
alert('The error was: ' + error.name +
'\n The error message was: ' + error.message);
} finally {
//do cleanup
}
}
The error object has two important properties: name and message. The message property contains the same
error message that we have seen before. The name property contains the kind of error that happened and we
can use that to decide if we know what to do with that error.

With that in place, if we reload the page and cancel out of the prompt, that's what we will see:

It's a good programming practice to only handle the error on the spot if you are certain of what it is and if
you actually have a way to take care of it (other than just suppressing it altogether.) To better target our
error handling code, we will change it to only handle errors named "TypeError", which is the error name
that we have identified for this bug.

function getInput(){
try {
var name = window.prompt('Type your name', '');
alert('Your name has ' + name.length + ' letters.');
} catch (error) {
if (error.name == 'TypeError') {
alert('Please try again.');
} else {
throw error;
}
} finally {
//do cleanup
}
}

Now if a different error happens, which is admittedly unlikely in this simple example, that error will not be
handled. The throw statement will forward the error as if we never had this try...catch...finally block. It is
said that the error will bubble up.

Throwing custom errors


We can use the throw statement to throw our own types of errors. The only recommendation is that our
error object also has a name and message properties to be consistent in error handling.

throw {
name: 'InvalidColorError',
message: 'The given color is not a valid color value.'
};

Debugging
One of the most important activities in software development is debugging. It can also be one of the most
costly. That's why we need to do our best to reduce the amount of time spent in debugging.

One way to reduce this time is to create automated unit tests, which we will see in the lesson Production
Grade JavaScript.

Another way is to use the best tools available and try to remove the pain associated with debugging. It used
to be the case that debugging tools for JavaScript were archaic or close to non-existent. This situation has
improved a lot and now we can confidently say we have feasible ways to debug JavaScript without
resorting to horrendous tactics, such as sprinkling alert() calls across our code.
We won't waste your time discussing all the existing tools for debugging. Instead we will focus on the tool
that singlehandedly re-wrote the JavaScript debugging history.

Firebug
Firebug is an extension for the Mozilla Firefox browser. Once installed, Firebug will turn Firefox into
almost an IDE for web development.

Let's learn about Firebug's capabilities by debugging an issue in practice.

Exercise: The Background Highlighter


Duration: 30 to 45 minutes.

In this exercise we are trying to understand why our BackgroundHighlighter object is not working as
expected. The object is supposed to change the background color of an input field when it gets focus and
revert it when it loses focus.

For some reason the code is not working. Here is the code.

Code Sample: ErrorHandlingAndDebugging/Exercises/bgnd-


changer.html
<html>
<head>
<title>Background Highlighter</title>
<style type="text/css">
.wc_debug
{
background-color:#ffc;
}
</style>
<script type="text/javascript" src="../../Libraries/DebugHelp.js" ></script>
<script type="text/javascript">
//add the debud panel at the bottom of the page
observeEvent(window, 'load', function () {insertDebugPanel();} );
</script>

<script type="text/javascript">
var BackgroundHighlighter = function (field, color) {
this.field = document.getElementById(field);
this.color = color;

this.field['onfocus'] = this.onGotFocus;
this.field['onblur'] = this.onLostFocus;
};
BackgroundHighlighter.prototype = {
onLostFocus: function () {
this.field.style.backgroundColor = '';
},
onGotFocus: function () {
this.field.style.backgroundColor = this.color;
}
};

function onPageLoad() {
//this function runs as soon as the page loads
new BackgroundHighlighter('userName', '#ff9');
new BackgroundHighlighter('company', '#ff9');
}
observeEvent(window, 'load', onPageLoad );

</script>

</head>

<body>
<form action="#">
Name: <input type="text" name="userName" value="" id="userName"/> <br/>
Company: <input type="text" name="company" value="" id="company">
</form>
</body>
</html>

1. Open the above file in Firefox.


2. Activate Firebug. Tools menu, Firebug, uncheck Disable Firebug (if checked) then Tools menu,
Firebug, Open Firebug.

Now if you click the Name textbox, Firebug will tell you that there's an error. See the picture below and
note the error message in the status bar.

The Console tab in Firebug shows that the error message is "this.field has no properties". The error
problem seems to be on line number 32.

Expand the error message by clicking the "+" icon next to it. We will get one extra piece of information, the
Call Stack, which in our case is simply one method call onGotFocus() as we can see in the image below.

When we click on onGotFocus() we will jump to the actual line of code in the Script tab. Let's place a
breakpoint on that line by clicking on the gutter on the left margin, right to the left of the line number.
Breakpoints are represented by a red circle on that margin.

Now let's click on the Name field again. Firebug kicks in an halts execution at the breakpoint we just set.

Looking at the Watch tab on the right, we can see that it is already tracking the value of this. And, to our
surprise, this does not contain a reference to an instance of our BackgroundHighlighter. Instead it contains
a reference to the input element.

Remember when we said you should be careful when using the this keyword in our objects? That was back
in The perils of this. Well, that is precisely the problem we are having right now. Our onGotFocus() method
is being called as an event handler for the onfocus event of the input field, and that call is made with the
input field being the value of this.

Our problem is not on line 32 though. The problem is back a few lines before:
this.field['onfocus'] = this.onGotFocus;
this.field['onblur'] = this.onLostFocus;

We cannot just pass a reference to one of our methods like that. We need to create some context that forces
the this inside those methods to contain our object. This is not hard. Let's change those two lines to:

var that = this;

this.field['onfocus'] = function() {
that.onGotFocus();
};

this.field['onblur'] = function() {
that.onLostFocus();
};

Now save the page and refresh the browser. The page should work now.

Where is the solution?

The Console tab

The console tab is an interactive interface between you and the executing code. It contains a prompt
denoted by >>> where you can inspect objects and variables, change their values, create new ones, etc.

Inspect DOM elements

The HTML tab allows us to inspect the page's structure. As we click elements in the displayed tree, they are
highlighted in the page right above. It is very useful to understand where in the page hierarchy a given
element is.

Inspect CSS

The CSS tab allows you to see all the CSS rules that exist on the page, from the various files that may
contain CSS, and you can change or disable any individual attribute. The effects of changing the attributes
are immediately reflected on the page. This feature is great for tweaking the CSS rules of your page to fix
CSS bugs.

All your scripts

Using the Scripts tab you can see all the scripts in the page and set breakpoints to assist during debugging.

Network traffic

One of the most interesting tabs is the Net tab. It shows all the requests made during the load and operation
of the page.

This tab is especially useful during the debugging of AJAX calls, where after expanding one of the requests
we can see all the HTTP traffic information for that particular request. The HTTP headers can become very
useful when tracing a problem.
Firebug has many more features but you're better off playing with it and learning which ones become more
useful to you. This tool is under active development, so make sure you check their site often to get newer
versions as they become available.

Error Handling and Debugging Conclusion


Dealing with software errors in one of those skills that can always be polished more. Beyond any natural
aptitude, the key to be effective in error handling is understanding the language support and the existing
development tools.

In case we didn't make it clear enough, we believe you should choose Firefox as your main development
browser and install Firebug immediately.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript
Tutorial's Table of Contents.
Production Grade JavaScript
In this lesson of the JavaScript tutorial, you will learn...

1. To choose the correct way to deliver JavaScript code


2. What Unobtrusive JavaScript is
3. Techniques to reduce page load times
4. To use existing tools for code documentation
5. To adopt coding style conventions
6. How to write and execute unit tests

As JavaScript becomes a larger part of your application, it's important that we treat it with the same care we
treat our server side code. We will see how to implement proper documentation, unit tests, coding
conventions, and a few other important aspects of any maintainable code base.

The way we include JavaScript in our pages can affect the page performance and we will be comparing the
various alternatives.

We will also look at a host of utilities to help us along the way, including debuggers and code pre-
processors.

JavaScript Delivery
As we have seen in the early lesson in our course, there are a few different ways of including JavaScript
code in our pages. Let's quickly revisit them.

Embedded in the page source

We can put our code inside script tags in our HTML markup. The code within these tags are evaluated as
they are encountered by the browser when loading the HTML, from top to bottom.

Syntax
<script type="text/javascript">
var MY_VAR = 123;
function doSomething() {
//.. code here
}
</script>

In external files

The code can also be placed in separate files that are retrieved and loaded by the browser when a script tag
with a src attribute is found.

Syntax
<script type="text/javascript" src="library.js"></script>

Inline in HTML tags

Sometimes we also see some script in attributes of HTML tags. These are usually there to handle some
event associated with the tag like a button's click.
Syntax
<input type="button"
value="Validate"
onclick="if(!validInput()) { alert('Please fix input');" />

Choosing between these options

Traditionally, the choice of delivery mechanism has always revolved around code reuse and client caching.

If we have scripts that are used in more than one page, then it is appropriate that we put these scripts in
external files and add them to each page.

There are two immediate benefits to this beyond the code reuse. First, the code will be maintained in a
single place, the .js file. Avoiding code duplication is always a good practice. Second, browsers will cache
the individual files, speeding up the page load process in subsequent visits.

Lately, though, there has been a lot of emphasis being placed on what has been called Unobtrusive
JavaScript. Read on.

Unobtrusive JavaScript

Current web development trends point to greater separation between content, style, and behavior. What that
means is removing as much as possible scripts from the HTML markup and placing them exclusively in
external files.

This may sound impossible, especially for the event handling scripts, but it's actually quite feasible. Take a
look at this "old school" event trickery.

<div id="editableTitle" onclick="enterEditMode(this);">


Click to Edit
</div>

This click event code can be moved to an external file with a relatively straight forward equivalent.

//this code is in an external file


window.load = function () {
var element = document.getElementById('editableTitle');
element.onclick = function () {
enterEditMode(element);
};
};

If we were using a helper library like Prototype.js, the code could become a little more compact.

//this code is in an external file


document.observe('dom:loaded', function () {
$('editableTitle').observe('click', function () {
enterEditMode(this);
});
});

The detail here is that our script can only reference DOM elements (like that div) after they are rendered.
The window object's load event is the appropriate place for that.

There's a problem here. If we have more than one external file trying to implement unobtrusive JavaScript,
it's possible that they hi-jack the window load event from each other. To avoid that we would recommend
using a helper library (again, like Prototype) to assign concurrent event handlers. Our Prototype.js-based
example above does just that.

The clean separation of HTML and JavaScript makes us recommend that you use the unobtrusive
JavaScript approach as much as possible. This practice tends to produce more organized and maintainable
JavaScript.

Performance implications
The presence of JavaScript in our pages directly affects how the browser loads and renders the page. As
soon as the browser finds a script tag in the HTML, it will stop rendering the HTML and will process that
JavaScript, which may involve downloading an external .js file. Even if the file had been previously cached
by the browser, it will still fetch it from the cache and then evaluate its contents.

The pauses in the page rendering can become quite noticeable depending on how many script tags we have
and where in the page they are located. This is compounded by the fact that many browsers only retrieve 2
files at most simultaneously.

Mitigation of performance issues


There are a few techniques to increase the efficiency of the page load process. Actually, what we are
talking here is the perceived performance of the page load. Studies have shown that most of the time taken
to load HTML pages is spent not retrieving the HTML file, but processing scripts and loading all the page's
external references, like CSS, JavaScript, and image files. In a very large number of sites the time to
retrieve and load the HTML text from the server is below 15% of the total time. Here we will look at
techniques that apply to JavaScript but some will apply to other file types as well.

Move scripts to the bottom of the page

Since the browser stops rendering the page when scripts are found, it makes sense that we try to place
scripts after most of the HTML has already been parsed and rendered.

The recommendation here is that we move our script tags as further down in the page as we can afford to
without breaking the scripts. If we are following unobtrusive JavaScript this should not be a problem at all.
We will put all the script tags immediately before the closing </body> tag.

This technique can be very easy to implement and it has a surprisingly effective result. It is a quick win that
we should not overlook.

Compress the files

Another way to speed up the load process of our pages is to compress the files that the page retrieves. In
terms of our external .js files, we should definitely remember to configure our web server to compress the
files before transmitting them.

When the browser requests a resource from the web server, it informs the web server about its de-
compression capabilities. This is done by sending a HTTP header like the following.

Syntax
Accept-encoding: gzip, deflate
If properly configured, as soon as the web server detects that header it will know it can return a compressed
version of the requested content. When compressed content is served, the response will carry a HTTP
header similar to the one below.

Syntax
Content-Encoding: gzip

The vast majority of the existing browsers will accept compressed content and de-compress it correctly. A
surprising number of web sites do not compress scripts and that has a negative effect on their performance.

Each web server is configured differently to enable the compression. We won't get into the details of how
to do that but you should not have any trouble finding the appropriate instructions in your web server's
documentation.

Minification of files

A similar technique is to minify our .js files. Minify was the term chosen to describe the process of
removing irrelevant white space and comments from JavaScript.

Note that we are not suggesting that we should stop adding comments to our JavaScript code or that we
remove all indentation at the same time. That would make our code incomprehensible even to its authors
(ourselves.)

The suggestion is that we use a utility to minify the code before it gets deployed on the server. We
definitely want to have the commented and indented code in our development environment, where we
typically do not experience the page load performance problems anyway.

JSMin

JSMin is one of the most popular tools to minify JavaScript code. On its web site you will find several
versions written in different programming languages. That includes a version written in JavaScript itself,
which we can try online at http://fmarcia.info/jsmin/test.html.

If you prefer, you can download the .exe version of JSMin and run it from the command line like this.

Syntax
jsmin.exe < myLibrary.js > myLibrary-minified.js

When we run JSMin on DebugHelp.js, which we have been using in many of our examples, we can see
what it does to reduce the file size. Here's the original file.

Code Sample: ProductionGradeJS/Demos/DebugHelp.js


/**
* @fileOverview
* @name DebugHelp.js
* @author Sergio Pereira sergio@sergiopereira.com
*/

/**
* Sets up an event handler for the given element.
* @param {DOM Element} target The element that will publish the event.
* @param {string} eventName The name of the event, like 'click', 'load', 'mouseover'.
* @param {function} observerFunction The function that will be invoked when the event
happens.
*/
function observeEvent(target, eventName, observerFunction){
if (target.addEventListener) {
target.addEventListener(eventName, observerFunction, false);
} else if (target.attachEvent) {
target.attachEvent('on' + eventName, observerFunction);
} else {
target["on" + eventName] = observerFunction;
}
}

/** The default id used for the debug div in case not explicitly set*/
var WC_DEFAULT_DEBUG_PANEL_ID = "wc_debug";

/**
* Inserts a div element to print debug messages inside a given element or
* at the bottom of the page.
* @param {string} [containerID] The element to create the div in.
* Defaults to the page body.
* @param {string} [debugPanelID] The id of the created div. Defaults to 'wc_debug'
*/
function insertDebugPanel(containerID, debugPanelID){
debugPanelID = debugPanelID||WC_DEFAULT_DEBUG_PANEL_ID;
var container = document.getElementById(containerID);
container = container||document.body;
var panel = document.createElement('DIV');
panel.id = debugPanelID;
panel.className = 'wc_debug';
container.appendChild(panel);
debugWrite('<h4 style=\"border-bottom:1px solid black;\">Output:</h4>', debugPanelID);
}

/** Appends a message to in the debug panel


* @param {string} message The HTML text to be printed
* @param {string} [debugPanelID] The id of the target debug panel,
* in case there's more than one. Defaults to 'wc_debug'.
*/
function debugWrite(message, debugPanelID){
debugPanelID = debugPanelID||WC_DEFAULT_DEBUG_PANEL_ID;
var panel = document.getElementById(debugPanelID);
var msgObj = document.createElement('P');
msgObj.innerHTML = message;
panel.appendChild(msgObj);
}

After we minify it using the online tool or jsmin.exe we get the following file.

Syntax
jsmin.exe < DebugHelp.js > DebugHelp-minified.js

Code Sample: ProductionGradeJS/Demos/DebugHelp-minified.js


function
observeEvent(target,eventName,observerFunction){if(target.addEventListener){target.addEve
ntListener(eventName,observerFunction,false);}else
if(target.attachEvent){target.attachEvent('on'+eventName,observerFunction);}else{target["
on"+eventName]=observerFunction;}}
var WC_DEFAULT_DEBUG_PANEL_ID="wc_debug";function
insertDebugPanel(containerID,debugPanelID){debugPanelID=debugPanelID||WC_DEFAULT_DEBUG_PA
NEL_ID;var
container=document.getElementById(containerID);container=container||document.body;var
panel=document.createElement('DIV');panel.id=debugPanelID;panel.className='wc_debug';cont
ainer.appendChild(panel);debugWrite('<h4 style=\"border-bottom:1px solid
black;\">Output:</h4>',debugPanelID);}
function
debugWrite(message,debugPanelID){debugPanelID=debugPanelID||WC_DEFAULT_DEBUG_PANEL_ID;var
panel=document.getElementById(debugPanelID);var
msgObj=document.createElement('P');msgObj.innerHTML=message;panel.appendChild(msgObj);}
The resulting file is clearly much smaller. Here's the comparison.

- Original Minified
Lines 55 3
Size in bytes 2057 945
Relative size 100% 45.9%

Note that the gains will vary according to the file contents. It's not rare to see the size shrink to below 30%
in files with good amounts of comments.

Obfuscation versus Minification

Some people may be uncomfortable with the fact that JavaScript code is delivered in clear text to the
browser. For this reason obfuscators were created.

An obfuscator will scan the source code, performs minification and renames a lot of the variables,
functions, etc. By using very short and cryptic names for the renamed items, an obfuscator reduces the code
size even more than a plain minifier.

Obfuscation is not without its problems. As you can imagine, renaming things in your code can be very
risky if that thing is being referenced outside the processed file.

We are not going to recommend obfuscation because of the unreasonable potential it has for introducing
bugs. A much better approach is to use minification combined with file compression. Compressed minified
files compared to compressed obfuscated ones are almost of the same size.

The intellectual property or security concerns that may prompt the use of an obfuscator aren't really
addressed by this tool. Obfuscation will only stop the casual observer and only slow down a little bit
anyone that is looking for vulnerabilities in your code.

Combine files

One simple way to speed up the page load is to reduce the number of external files referenced by the
HTML. Since the browser downloads only a few files simultaneously, if we minimize the number of
downloads we will be contributing to the faster rendering of the page.

Both JavaScript and CSS files are good candidates to be combined in one big file of each kind. If your page
or site uses a big number of small .js files, consider combining all of them into a single larger file.

Although pretty obvious, this is our number one recommendation for effectively use and deliver JavaScript
in your pages. Do all you can to serve your .js files concatenated. Most server side technologies like
ASP.NET and Ruby on Rails will provide you with an easy way to do this, even if you prefer to keep them
separated during development.

More techniques

There are a few more techniques that you can apply to make your pages load faster. We would like to
recommend that you take a look at YSlow, which is a Firefox extension that will try to identify
performance problems in your pages and suggest some improvements.
Documenting JavaScript
If we plan to create our own JavaScript libraries that can be reused across projects and by more than one
developer, it becomes important that we provide some level of documentation for them.

Documentation is one of those things that quickly gets out of synch with the actual code unless these two
things are kept close to each other. One popular way to do this is to include the source code documentation
in comments embedded in the code. A tool is later run to extract all these comments and produce browsable
documentation. Because the documentation is maintained within the code itself, it increases the chances
that the documentation reflects the current code.

JsDoc Toolkit
Early on there was a tool called JSDoc that would do just that but it has one mild problem, it was written in
Perl, what didn't help its popularization. Recently, a similar tool, that uses the same comment format, was
written in JavaScript and invoked via Java. This tool is called JsDoc Toolkit and can be found at
http://jsdoctoolkit.org

That web site will provide you with all the documentation and samples. As you can imagine, you'll need to
have some recent version of Java installed in your system, which you probably already do anyway.

Exercise: Using JsDoc Toolkit on DebugHelp.js


Duration: 20 to 30 minutes.

To demonstrate this tool, let's generate the documentation for DebugHelp.js, which we have already seen in
some of our examples.

1. Your class material includes the following file with JsDoc Toolkit:
ClassFiles\ProductionGradeJS\Exercises\jsdoc-toolkit.zip
2. Extract all files from this .zip file into a directory named jsdoc-toolkit in that same directory
(Exercises.)
3. The utility is run from the command line but it takes too many parameters. Let's create a file
named buildDocs.bat so that we can simply pass a file or directory name to the tool.
4. Execute the above .bat file to generate the documentation for DebugHelp.js.
5. Open a command line and go to ClassFiles\ProductionGradeJS\Exercises
6. Execute buildDocs DebugHelp.js

After running the command, you should see a new directory called docs under Exercises. Inside that
directory, find and open the file index.html on your browser and you should see the generated
documentation, just like the screen shot below.

Code Sample: ProductionGradeJS/Exercises/DebugHelp.js


/**
* @fileOverview
* @name DebugHelp.js
* @author Sergio Pereira sergio@sergiopereira.com
*/
/**
* Sets up an event handler for the given element.
* @param {DOM Element} target The element that will publish the event.
* @param {string} eventName The name of the event, like 'click', 'load', 'mouseover'.
* @param {function} observerFunction The function that will be invoked when the event
happens.
*/
function observeEvent(target, eventName, observerFunction){
if (target.addEventListener) {
target.addEventListener(eventName, observerFunction, false);
} else if (target.attachEvent) {
target.attachEvent('on' + eventName, observerFunction);
} else {
target["on" + eventName] = observerFunction;
}
}

/** The default id used for the debug div in case not explicitly set*/
var WC_DEFAULT_DEBUG_PANEL_ID = "wc_debug";

/**
* Inserts a div element to print debug messages inside a given element or
* at the bottom of the page.
* @param {string} [containerID] The element to create the div in.
* Defaults to the page body.
* @param {string} [debugPanelID] The id of the created div. Defaults to 'wc_debug'
*/
function insertDebugPanel(containerID, debugPanelID){
debugPanelID = debugPanelID||WC_DEFAULT_DEBUG_PANEL_ID;
var container = document.getElementById(containerID);
container = container||document.body;
var panel = document.createElement('DIV');
panel.id = debugPanelID;
panel.className = 'wc_debug';
container.appendChild(panel);
debugWrite('<h4 style=\"border-bottom:1px solid black;\">Output:</h4>', debugPanelID);
}

/** Appends a message to in the debug panel


* @param {string} message The HTML text to be printed
* @param {string} [debugPanelID] The id of the target debug panel,
* in case there's more than one. Defaults to 'wc_debug'.
*/
function debugWrite(message, debugPanelID){
debugPanelID = debugPanelID||WC_DEFAULT_DEBUG_PANEL_ID;
var panel = document.getElementById(debugPanelID);
var msgObj = document.createElement('P');
msgObj.innerHTML = message;
panel.appendChild(msgObj);
}
Where is the solution?

Coding Standards
It's common for many organizations to establish coding standards across the development team. It's also
very common for developers to disagree and even ignore these standards. When writing JavaScript code,
trust me, some standards are actually very much necessary.

Because of its flexible nature and also because of some evil implementations of JavaScript by the browsers,
it is way too easy to fall into traps and create bugs that are very hard to trace.

Let's go through some of the most important JavaScript coding standards that we would like to encourage
you to follow. Some are there for pure legibility and some are there for your own protection.
Avoid globals at all costs
Global variables are the hallmark of badly structured code. They might be acceptable when the use of
JavaScript in the page is limited, but as the usage grows, global variables are dangerous and can produce
unexpected behavior.

Especially when we have more than one external .js file being used in the page, nothing prevents the code
in one file from declaring a global variable or function with the same name as in another file.

To remove this problem from our code we suggest, interestingly enough, that we create global namespacing
objects. See the following example.

//in wc_library.js
var COMPANY_NAME = 'Webucator';
function doSomething() {
//...
}

//in amazon.js
var COMPANY_NAME = 'Amazon.com';
function doSomething() {
//...
}

As we can see, if we include both files (wc_library.js and amazon.js) in the same page they will clobber
each other and who knows what the consequences will be. See how namespacing objects would avoid that
problem.

//in wc_library.js
var WEBUCATOR = {
companyName: 'Webucator'
doSomething: function () {
//...
}
};

//in amazon.js
var AMAZON = {
companyName: 'Amazon.com',
doSomething: function () {
//...
}
};

Now, instead of globals, we have methods and properties, locked inside well-organized objects. They are
the only type of global objects we want to encourage.

Use === and !== instead of == and !=


As we have already seen in a previous lesson, the use of == and != can sometimes lead to unintended
results because of automatic type coercion. To avoid this risk, use their longer cousins === and !==, they
are well worth the extra character.

Avoid eval()
This is another problem we discussed previously. Again, just remember, eval() is evil.
Do not pass strings to setTimeout() or setInterval()
Passing strings to these functions is just another form of eval() in disguise. Instead of a string with
JavaScript code, pass an actual function variable or an anonymous function.

//instead of this:
setTimeout("alert('Time is up!');", 9000);
//prefer this:
setTimeout( function () {alert('Time is up');}, 9000);

Use the default operator ||


The use of the default operator is very common in high-quality JavaScript libraries and we should get used
to employ it in our code as well.

Do not use assignments as expressions


Assignments used as expressions can be hard to understand and, worse, be confused with bugs. Do not use
them like that. See how the following if statement looks like a bug where the developer forgot to use a ==
(or a ===).

if (flag = getFlag() ) {
alert(flag);
}

Use the ternary operator for value selection


The ternary operator is a good space saver. Use it instead of trivial if / else blocks.

//instead of this:
var x;
if (flag) {
x = 'success';
} else {
x = 'failure';
}
//prefer this:
var x = flag ? 'success' : 'failure';

Limit the amount of embedded JavaScript


Only use embedded JavaScript in the HTML when the JavaScript is only useful for the current page and
session.

Constrain lines to 80 characters


• Break lines right after operators or comma
• Indent the line after a line break with one extra tab

Use comments judiciously


• Add meaningful comments
• Avoid obvious comments
• Prefer inline comments //

Declare all variables at the beginning of each function


Since JavaScript only has function scope, declaring variables inside other blocks, like if or for may give the
false impression that the variable is scoped inside that block, which could lead to bugs.

Start constructor functions with a capital letter


Since constructor functions need to be called preceded by the new operator, we use its initial upper case
character as a reminder that we are dealing with a constructor. This should help us remembering to use the
new operator.

Use blocks all the time in control structures


Control structures like if, while or for can take either a single statement or a block of statements inside
curly braces.

We recommend that you always use a block, even if it has only one statement. The absence of the braces
can hide bugs or make the code look different than its intent.

Naming your identifiers


• Use only A-Za-z0-9_ for identifiers
• Don't start identifiers with _
• Don't use $ or \
• Start constructors with upper case
• Global variables in ALL_CAPS
• Start all other identifiers with lower case

Use whitespace wisely


• Between any keyword and a (, like for ( ... )
• No spaces between a function name and the parenthesis: execute(abc)
• Put a space after a comma
• Each ; in the control part of a for statement should be followed with a space.

Use {} instead of new Object()


Syntax
//instead of
var APPOINTMENT = new Object();
APPOINTMENT.title = 'Team Meeting';
//prefer this:
var APPOINTMENT = { };
APPOINTMENT.title = 'Team Meeting';

Use [] instead of new Array()


Syntax
//instead of
var BOOKS = new Array();
BOOKS[0] = 'Ship It!';
//prefer this:
var BOOKS = [ ];
BOOKS[0] = 'Ship It!';

Format of common code structures


format of the if statement

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

format of the for statement

Syntax
for (initialization; condition; update) {
statements;
}

for (variable in object) if (filter) {


statements;
}

format of the while statement

Syntax
while (condition) {
statements;
}

format of the do statement

Syntax
do {
statements;
} while (condition);

format of the switch statement

Syntax
switch (expression) {
case expression:
statements;
break; //(or return or throw)
default:
statements;
}

format of the try statement:

Syntax
try {
statements;
} catch (variable) {
statements;
} finally {
statements;
}

Checking code with JSLint


Many of the coding conventions that we just discussed can be verified by a tool called JSLint.

JSLint will analyze your JavaScript code and warn you of any unadvisable practices present in the code. It
has quite a few options for you to ignore some of the rules if desired.

Unit Testing JavaScript


A growing number of developers are using automated unit testing frameworks to test their code. Some of
these developers are practitioners of Test-Driven Development (TDD.)

Adopters of TDD write the unit tests before they write the code. The idea is that this will force you to write
code that is testable, which happens to also be better designed code in most cases.

Unit testing is especially attractive to code written in dynamic languages like JavaScript. There's just too
much flexibility in JavaScript and there isn't a compiler to give you a minimum level of confidence that
your code is correct. You have to actually run the code after every change to be certain you didn't break
anything.

This is where unit testing frameworks are helpful. We will take a look at the most popular one, called
JsUnit. If you have used any other testing framework of the x-Unit family, you should feel right at home in
JsUnit.

JsUnit comes with a series of functions that you can use in your unit testing scripts. The process typically
involves creating a new HTML page to hold a group of your tests, add the required JsUnit scripts
references, and write a few functions to perform the actual tests. These functions have to be named starting
with "test" (there are ways around this).

To execute the tests and see the results, we use the test runner and ask it to load the page with the tests. The
test runner will find the "testXXXXXXX" functions and call one by one, collecting the results and
reporting progress and results in a red or green progress bar.

To demonstrate how this works, look at this test file, which tests a couple of methods of the FaderEffect
object we saw in an earlier lesson. We included JsUnit in the class files for this lesson.

Code Sample: ProductionGradeJS/Demos/js-unit.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
<title>Tests for Yellow Fade Effect</title>
<script type="text/javascript" src="../jsunit/app/jsUnitCore.js" ></script>
<script type="text/javascript" src="faderEffect.js" ></script>
<script type="text/javascript" charset="utf-8">

function test_intToColorByte() {
var el = document.getElementById('testElement');
var effect = new FaderEffect(el, 2, '#010203', '#0f0e0d');
assertEquals('Convert number lower than 16', '0a', effect.intToColorByte(10));
assertEquals('Convert number greater than 16', '20', effect.intToColorByte(32));
}

function test_colorToArray() {
var el = document.getElementById('testElement');
var effect = new FaderEffect(el, 2, '#010203', '#0f0e0d');
var array = effect.colorToArray('#04FF01')
assertEquals('Convert RED element', 4, array[0]);
assertEquals('Convert GREEN element', 255, array[1]);
assertEquals('Convert BLUE element', 1, array[2]);
}
</script>
</head>

<body>
<div id="testElement"></div>
</body>
</html>

Code Sample: ProductionGradeJS/Demos/faderEffect.js


function FaderEffect(element, duration, fromColor, toColor) {
var that = this;
this.element = element;
this.interval = 100;
this.duration = 1000 * (duration || 1);
this.fromColor = fromColor || '#ffff99';
this.toColor = toColor || '#ffffff';
this.totalFrames = Math.round(this.duration / this.interval);

this.intToColorByte = function (num) {


var digits = num.toString(16);
if (num < 16) {
digits = '0' + digits;
}
return digits;
};

this.colorToArray = function (color) {


return [
this.parseColorByte(color, 0),
this.parseColorByte(color, 1),
this.parseColorByte(color, 2)
];
}

this.parseColorByte = function (color, whichByte) {


return parseInt(color.substr(1 + whichByte*2, 2), 16);
};

this.arrayToColor = function (arr) {


return '#' +
this.intToColorByte(arr[0]) +
this.intToColorByte(arr[1]) +
this.intToColorByte(arr[2]);
};

this.fromRGB = this.colorToArray(this.fromColor);
this.toRGB = this.colorToArray(this.toColor);
this.frameNo = 0;

this.updateBgColor = function () {
if (that.frameNo < (that.totalFrames-1)) {
var newRGB = that.calcNewColor(that.frameNo);
that.element.style.backgroundColor = that.arrayToColor(newRGB);
that.frameNo += 1;
setTimeout(that.updateBgColor, that.interval);
} else {
that.element.style.backgroundColor = that.arrayToColor(that.toRGB);
}
};

this.calcNewColor = function () {
var frac = (1.0 * this.frameNo)/this.totalFrames;
return [
Math.floor((this.toRGB[0]-this.fromRGB[0])*frac + this.fromRGB[0]),
Math.floor((this.toRGB[1]-this.fromRGB[1])*frac + this.fromRGB[1]),
Math.floor((this.toRGB[2]-this.fromRGB[2])*frac + this.fromRGB[2])
];
};

this.updateBgColor();
}

To use the test runner you will need to have Java installed in your machine. With that, navigate to
ProductionGradeJS/jsunit/testRunner.html, select the file ProductionGradeJS/Demos/js-unit.html and click
"Run". You should see something similar to the image below.

Unit testing, and TDD in special, are very large topics for which many books have been written. Our goal
here is to simply show you that, unit testing is a very good practice for JavaScript code and that there's is
support similar to other programming languages.

Production Grade JavaScript Conclusion


The days of JavaScript being written and maintained in sloppy fashion are gone. There aren't reasonable
excuses to treat your JavaScript code with any less care than the server side code.

With the available tools and guidance you can produce very maintainable JavaScript and abandon the
practice of blindly copying and pasting JavaScript (if you've been in web development for long enough,
you know you've done it.)

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript
Tutorial's Table of Contents.
The Prototype Library
In this lesson of the JavaScript tutorial, you will learn...

1. What is, who wrote, who uses, who maintains


2. The extensions to core JavaScript objects
3. How much more powerful strings can be
4. New ways to work with lists of items
5. Simulate class-based inheritance
6. The handy utility functions
7. Extensions to the DOM elements
8. How to do Ajax with Prototype
9. How to extend Prototype
10. Where to get more information

Back in 2005, when the Web rediscovered JavaScript and the AJAX term was coined, a few JavaScript
libraries emerged as the platform behind many of the new web sites collectively known as Web 2.0. One of
the most popular libraries, arguably the most popular at the time, was Prototype.

The Prototype library was originally written by Sam Stephenson when the company he worked for was
creating some of the most well-known pioneer AJAX applications, like Basecamp and Campfire. This
library is also what powers the client side scripts of applications built using Ruby on Rails.

Today the library is still maintained by Sam Stephenson but now it has its own team of maintainers that
continuously contribute new features, bug fixes, and tools to produce JavaScript with Prototype.

Prototype is largely a framework type of library. It does not have any eye candy or UI widgets. On the
other hand, because it is a good platform, there is a full blown ecosystem of other libraries built on top of
Prototype to provide almost anything you need at the client side.

During this lesson and the next, whenever we are referring to the Prototype library we will use the word
with a capital P. We will use lower case prototype to refer to the prototype property that all JavaScript
objects have.

Base Class Inheritance


We spent quite a bit of time explaining how the prototypal inheritance works in JavaScript and how it
differs from the classical model. Future version of JavaScript are expected to support base class inheritance.
Until then, Prototype comes with an implementation of the classical inheritance model with the intent of
creating a more familiar environment for the developers that choose not to apply prototypal inheritance.

Creating classes
Prototype comes with an object named Class that we can use to create new classes and optionally specify
their base classes.

var WEBUCATOR = { };
WEBUCATOR.Beverage = Class.create( {
initialize: function (name) {
this.name = name;
},
describe: function () {
return "I'm a beverage named " + this.name + ".";
}
});
var water = new WEBUCATOR.Beverage('Water');
alert(water.describe());

The object passed to Class.create will become the implementation of the class, copied to the new class'
prototype object. The only special method is the one called initialize(); it will serve as the class' constructor.

Class inheritance
If the object passed to Class.create is another class object created with Class.create, that will be detected
and this object (class) will become the base class for the new class.

We can add new members or replace members in the base class by using a second argument containing an
object. When we are replacing methods in the new class, we can define the first argument of the new
method called $super, which will be a reference to the same method in the base class. We can call it if
needed. The example below shows all that in action.

Code Sample: PrototypeJS/Demos/dollar-function.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
<title> Test Page </title>
<script src="../../Libraries/prototype.js" type="text/javascript"></script>
<script src="../../Libraries/DebugHelp.js" type="text/javascript"></script>
<script type="text/javascript">
function test() {
var d = $('myDiv');
d.hide();
alert(d.innerHTML);
d.show();
d.addClassName('active');
}
//add the debud panel at the bottom of the page
observeEvent(window, 'load', function () {insertDebugPanel();} );
</script>
<style type="text/css" media="screen">
.active {background-color:#ff9;}
</style>
</head>
<body>
<div id="myDiv">
<p>This is a paragraph</p>
</div>
<div id="myOtherDiv">
<p>This is another paragraph</p>
</div>
<input type="button" value="Test $()" onclick="test();"/><br/>
</body>
</html>

This type of classical inheritance is used extensively in Prototype's source code, in case you are curious to
inspect it (and we encourage you to do so.)

The utility functions


The library comes with many predefined objects and utility functions. The obvious goal of these functions
is to save you a lot of repeated typing and idioms.

Using the $() function


The $() function is a handy shortcut to the all-too-frequent document.getElementById() function of the
DOM. Like the DOM function, this one returns the element that has the id passed as an argument.

Unlike the DOM function, though, this one goes further. The returned element object will be augmented
with some extra methods. These extra methods simplify many tasks, like hiding/showing the element,
getting its size, scrolling to the element, etc. You can get a list of the methods that are added to the returned
element object in the reference for the Element.Methods object. Furthermore, if the element is a form it will
also receive copies of the utility methods from Form.Methods and if the element is a form field (input,
select, or textarea) it will additionally receive copies of the utility methods from Form.Element.Methods.

Code Sample: PrototypeJS/Demos/dollar-function.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
<title> Test Page </title>
<script src="../../Libraries/prototype.js" type="text/javascript"></script>
<script src="../../Libraries/DebugHelp.js" type="text/javascript"></script>
<script type="text/javascript">
function test() {
var d = $('myDiv');
d.hide();
alert(d.innerHTML);
d.show();
d.addClassName('active');
}
//add the debud panel at the bottom of the page
observeEvent(window, 'load', function () {insertDebugPanel();} );
</script>
<style type="text/css" media="screen">
.active {background-color:#ff9;}
</style>
</head>
<body>
<div id="myDiv">
<p>This is a paragraph</p>
</div>
<div id="myOtherDiv">
<p>This is another paragraph</p>
</div>
<input type="button" value="Test $()" onclick="test();"/><br/>
</body>
</html>

Because many of the new methods added to the element return the element itself, you can chain the method
calls to make more compact code:

//change the text, the CSS class, and make the element visible
$('messageDiv').update('Your order was accepted.').addClassName('operationOK').show();

Another nice thing about this function is that you can pass either the id string or the element object itself,
which makes this function very useful when creating other functions that can also take either form of
argument.

Using the $$() function


The $$() function will help you a lot if you consistently separate CSS from the content wireframe. It parses
one or more CSS filtering expressions, analogous to the ones used to define CSS rules, and returns the
elements that match these filters.

It's so easy to use it's ridiculous. Check this out.

Code Sample: PrototypeJS/Demos/double-dollar-function.html


---- Code Omitted ----
<script type="text/javascript">
function test$$() {
/*
in case CSS is not your forte, the expression below says
'find all the INPUT elements that are inside
elements with class=field that are inside a DIV
with id equal to loginForm.'
*/
var f = $$('div#loginForm .field input');
var s = '';
for (var i=0; i<f.length; i++) {
s += f[i].value + '/';
}
debugWrite(s); // shows: "joedoe1/secret/"

//now passing more than one expression


f = $$('div#loginForm .field input', 'div#loginForm .fieldName');
s = '';
for (var i=0; i<f.length; i++) {
s += ( f[i].value ? f[i].value : f[i].innerHTML ) + '/';
}
debugWrite(s); //shows: "joedoe1/secret/User name:/Password:/"
}
---- Code Omitted ----
<div id='loginForm'>
<div class='field'>
<span class='fieldName'>User name:</span> <input type='text' id='txtName'
value='joedoe1'>
</div>
<div class='field'>
<span class='fieldName'>Password:</span> <input type='password' id='txtPass'
value='secret'>
</div>
<input type='submit' value='login'>
</div>

<input type="button" value='test $$()' onclick='test$$();'>


---- Code Omitted ----

A quick note on performance. The current implementation of the $$() function in prototype.js is not
regarded as particularly efficient. If you plan on traversing deep and complex HTML documents using this
function frequently, you may want to consider other freely available implementations, possibly simply
substituting the $$() function itself.

Using the $F() function


The $F() function is another welcome shortcut. It returns the value of any field input control, like text
boxes or drop-down lists. The function can take as argument either the element id or the element object
itself.

Code Sample: PrototypeJS/Demos/f-dollar-function.html


---- Code Omitted ----
<script type="text/javascript">
function test3() {
debugWrite( $F('userName') );
}
</script>
<form>
<input type="text" id="userName" value="Joe Doe"><br/>
<input type="button" value="Test3" onclick="test3();"><br/>
</form>
</body>
</html>

Using the $A() function


The $A() function converts the single argument it receives into an Array object.

This function, combined with the extensions for the Array class, makes it easier to convert or copy any
enumerable list into an Array object. One suggested use is to convert DOM NodeLists into regular arrays,
which can be traversed more efficiently. See example below.

<script type="text/javascript">
function showOptions() {
var someNodeList = $('lstEmployees').getElementsByTagName('option');
var nodes = $A(someNodeList);

nodes.each( function (node) {


alert(node.nodeName + ': ' + node.innerHTML);
});
}
</script>
<select id="lstEmployees" size="10" >
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>
<input type="button" value="Show the options" onclick="showOptions();" >

Using the $H() function


The $H() function converts objects into enumerable Hash objects that resemble associative arrays (a.k.a.
hashes or hash tables.)

function testHash() {
//let's create the object
var a = {
first: 10,
second: 20,
third: 30
};

//now transform it into a hash


var h = $H(a);
alert(h.toQueryString()); //displays: first=10&second=20&third=30
}

Using the $R() function


The $R() function is simply a short hand to writing new ObjectRange(lowerBound, upperBound,
excludeBounds).
Jump to the ObjectRange class documentation for a complete explanation of this class. In the meantime,
let's take a look at a simple example that also shows the usage of iterators through the each method. More
on that method will be found in the Enumerable object documentation.

<script type="text/javascript">
function demoDollar_R() {
var range = $R(10, 20, false);
range.each( function (value, index) {
alert(value);
});
}
</script>
<input type="button" value="Sample Count" onclick="demoDollar_R();" />

Using the Try.these() function


The Try.these() function makes it easy when you want to, ahem, try different function calls until one of
them works. It takes a number of functions as arguments and calls them one by one, in sequence, until one
of them works, returning the result of that successful function call.

In the example below, the function xmlNode.text works in some browsers, and xmlNode.textContent works
in the other browsers. Using the Try.these() function we can return the one that works.

<script type="text/javascript">
function getXmlNodeValue(xmlNode) {
return Try.these(
function () {return xmlNode.text;},
function () {return xmlNode.textContent;}
);
}
</script>

Strings, reloaded
Strings are powerful objects. Prototype takes that power and elevates it by another level of magnitude.

String substitutions
When it comes string substitutions JavaScript already has the methods like String.Replace, which even
works with regular expressions, but it's still not as flexible as the alternative introduced by Prototype.

Meet the new String.gsub method. With this method you can not only find and replace a fixed string or a
regular expression pattern, but you also have much more control over the replacement process. You can, for
example, use a string template to instruct the method on how you would like the found elements to be
transformed (rather than simply replaced.)

The example below searches for words containing 't' and replaces the portion that comes after the 't' with
'tizzle'. In case the example is not very clear, the regular expression we chose has a capture group
declaration: the \w+ enclosed in parenthesis. We can get the value captured by this group using #{1} in the
replacement template string.

In our example we are capturing what comes before the 't' and appending 'tizzle' to it. If we had more
capture groups in the regular expression, we would get the values with #{2}, #{3}, and so on.

function talkLikeYouKnowSomething() {
var s = 'prototype string extensions can help you';
var snoopdogfy = /\b(\w+)t\w+\b/;
var snooptalk = s.gsub(snoopdogfy, '#{1}tizzle' );
alert(snooptalk); // shows: "prototizzle stizzle extizzle can help you"
}

Let's not stop there. The substitution we have just made is not all that powerful because we are limited to
pattern matching and substitutions. What if we could operate on the matches with custom logic to produce
the desired substitution values? We can do that if we pass a function as the second argument to gsub(). The
function will receive an array with the matched text (index 0) and any capture group values (index 1 to N.)

function scamCustomers() {
var prices = 'book1 $12.5, magazine $5.50, pencil $1.20';
var priceFinder = /\$([0-9\.]+)/;
var r = prices.gsub(priceFinder, jackUp);
alert(r);//shows: "book1 $13.75, magazine $6.05, pencil $1.32"
}

function jackUp(matches) {
//increases the prices by 10%
var price = parseFloat(matches[1]);
return '$' + Math.round(110 * price)/100;
}

String templates
As you increase the amount of JavaScript code in your applications, increasingly you'll find yourself with
collections of objects of the same type and that you need to list or present in a formatted way.

It's not rare to find code in your applications that loops through a list of objects, building a string based on
the object properties and some fixed formatting elements. Prototype comes with the Template class, which
aims at helping you with exactly this type of scenarios.

The example below shows how to format a list of items in a shopping cart in multiple HTML lines.

function printCart() {
//creating a sample cart
var cart = { };
cart.items = [ ];
//putting some sample items in the cart
cart.items.push({product: 'Book 123', price: 24.50, quantity: 1});
cart.items.push({product: 'Set of Pens', price: 5.44, quantity: 3});
cart.items.push({product: 'Gift Card', price: 10.00, quantity: 4});

//here we create our template for formatting each item


var itemFormat = new Template(
'You are ordering #{quantity} units ' +
'of #{product} at $#{price} each'
);
var formatted = '';

for (var i=0; i<cart.items.length; i++) {


var cartItem = cart.items[i];
formatted += itemFormat.evaluate(cartItem) + '<br/>\n';
}

alert(formatted);
/* SHOWS:
You are ordering 1 units of Book 123 at $24.5 each<br/>
You are ordering 3 units of Set of Pens at $5.44 each<br/>
You are ordering 4 units of Gift Card at $10 each<br/>
*/
}
For a more complete list of new methods, see the String extensions reference.

DOM Manipulation
Another great strength of Prototype is it's repertoire of methods to assist with dynamically changing the
HTML document structure.

We've already sees that Prototype augments the DOM elements with a host of utility methods. Many of
those methods are related to DOM traversing and manipulation. We can create, show, hide, alter elements
in our HTML with a much simpler syntax than the one that comes as part of the DOM API.

We can get a lot done with a few basic methods with suggestively enough names: insert(), show(), hide(),
remove(), update(), and wrap(). We also can create elements from scratch using the new Element(tagName)
syntax.

All of these DOM operations are shown in the following example. Once again, note how we can chain
these method calls to reduce the amount of code typed.

Code Sample: PrototypeJS/Demos/DOM.html


---- Code Omitted ----
<h4>Creating new elements</h4>
<script type="text/javascript" charset="utf-8">
function createElem() {
var el = new Element('img', {src:'wc.png'});
$('box1').appendChild(el);
}
</script>
<input type="button" name="btn1" value="Create img element" id="btn1"
onclick="createElem();">
<div id="box1" class="" ></div>

<h4>Insertions</h4>
<script type="text/javascript" charset="utf-8">
function insertElTop() {
var el = new Element('li').update( $F('newItem') );
$('list1').insert({top: el });
}

function insertElBottom() {
var el = new Element('li').update( $F('newItem') );
$('list1').insert({bottom: el });
}

function insertElBefore() {
var el = new Element('li').update( $F('newItem') );
$('list1').insert({before: el });
}

function insertElAfter() {
var el = new Element('li').update( $F('newItem') );
$('list1').insert({after: el });
}
</script>
<input type="text" name="newItem" value="Text here" id="newItem"/>&nbsp;
<input type="button" value="Insert at TOP" id="btn2a" onclick="insertElTop();" />
<input type="button" value="Insert at BOTTOM" id="btn2b" onclick="insertElBottom();" />
<input type="button" value="Insert BEFORE" id="btn2c" onclick="insertElBefore();" />
<input type="button" value="Insert AFTER" id="btn2d" onclick="insertElAfter();" />

<div style="border:solid 1px black;">


<ol id="list1">
<li>Existing item #1</li>
<li>Existing item #2</li>
</ol>
</div>

<h4>Hide/Show</h4>
<input type="button" value="Hide" onclick="$('box3').hide();" />
<input type="button" value="Show" onclick="$('box3').show();" />
<input type="button" value="Toggle" onclick="$('box3').toggle();" />
<div class="bigBox"><div id="box3" class="smallBox" />&nbsp;</div>

<h4>Wrapping</h4>
<script type="text/javascript" charset="utf-8">
function wrapInDiv() {
$('img4').wrap('div', {'class':'lightBox'});
}
</script>
<input type="button" value="Wrap in Div" onclick="wrapInDiv();" />
<div style="width:330px;">
<img id="img4" src="wc.png" alt="webucator"/>

<h4>Removing elements</h4>
<script type="text/javascript" charset="utf-8">
function removeEl() {
try {
$('img5').remove();
} catch (ex) {
alert('The element does not exist!!!!');
}
}
</script>
<input type="button" value="Remove Image" onclick="removeEl();" />

<img id="img5" src="wc.png" alt="webucator"/>


---- Code Omitted ----

The Ajax object


The utility functions mentioned above are nice but, let's face it, they are not the most advanced type of
thing, now are they? You could probably have done it yourself and you may even have similar functions in
your own scripts. But those functions are just the tip of the iceberg.

I'm sure that your interest in Prototype is driven mostly by its AJAX capabilities. So let's explain how the
library makes your life easier when you need to perform AJAX logic.

The Ajax object is a pre-defined object, created by the library to wrap and simplify the tricky code that is
involved when writing AJAX functionality. This object contains a number of classes that provide
encapsulated AJAX logic. Let's take a look at some of them.

Using the Ajax.Request class


If you are not using any helper library, you are probably writing a whole lot of code to create a
XMLHttpRequest object and then track its progress asynchronously, then extract the response and process
it. And consider yourself lucky if you do not have to support more than one type of browser.

To assist with AJAX functionality, the library defines the Ajax.Request class.
Let's say you have an application that can communicate with the server via the url
http://yourserver/app/get_sales?empID=1234&year=1998, which returns an XML response like the
following.

<?xml version="1.0" encoding="utf-8" ?>


<ajax-response>
<response type="object" id="productDetails">
<monthly-sales>
<employee-sales>
<employee-id>1234</employee-id>
<year-month>1998-01</year-month>
<sales>$8,115.36</sales>
</employee-sales>
<employee-sales>
<employee-id>1234</employee-id>
<year-month>1998-02</year-month>
<sales>$11,147.51</sales>
</employee-sales>
</monthly-sales>
</response>
</ajax-response>

Talking to the server to retrieve this XML is pretty simple using an Ajax.Request object. The sample below
shows how it can be done.

<script type="text/javascript">
function searchSales() {
var empID = $F('lstEmployees');
var y = $F('lstYears');
var url = 'http://yourserver/app/get_sales';
var pars = 'empID=' + empID + '&year=' + y;

var myAjax = new Ajax.Request(


url,
{
method: 'get',
parameters: pars,
onComplete: showResponse
});

function showResponse(response) {
//put returned XML in the textarea
$('result').value = response.responseText;
}
</script>
<select id="lstEmployees" size="10" onchange="searchSales()">
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>
<select id="lstYears" size="3" onchange="searchSales()">
<option selected="selected" value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
</select>
<br/><textarea id="result" cols=60 rows=10 ></textarea>

Can you see the second parameter passed to the constructor of the Ajax.Request object? The parameter
{method: 'get', parameters: pars, onComplete: showResponse} represents an anonymous object in literal
notation (a.k.a. JSON). What it means is that we are passing an object that has a property named method
that contains the string 'get', another property named parameters that contains the querystring of the HTTP
request, and an onComplete property/method containing the function showResponse.
There are a few other properties that you can define and populate in this object, like asynchronous, which
can be true or false and determines if the AJAX call to the server will be made asynchronously (the default
value is true.)

This parameter defines the options for the AJAX call. In our sample, we are calling the url in the first
argument via a HTTP GET command, passing the querystring contained in the variable pars, and the
Ajax.Request object will call the showResponse function when it finishes retrieving the response.

As you may know, the XMLHttpRequest reports progress during the HTTP call. This progress can inform
four different stages: Loading, Loaded, Interactive, or Complete. You can make the Ajax.Request object
call a custom function in any of these stages, the Complete being the most common one. To inform the
function to the object, simply provide property/methods named onXXXXX in the request options, just like
the onComplete from our example. The function you pass in will be called by the object with two
arguments, the first one will be an Ajax.Response object (the response) and the second one will be the
evaluated X-JSON response HTTP header (if one is present). You can then use the first argument to get the
returned data and maybe check the status property, which will return the HTTP result code of the call. The
X-JSON header is useful if you want to return some script or JSON-formatted data. The same JSON data is
also available in the response's responseJSON property.

Two other interesting options can be used to process the results. We can specify the onSuccess option as a
function to be called when the AJAX call executes without errors and, conversely, the onFailure option can
be a function to be called when a server error happens. Just like the onXXXXX option functions, these two
will also be called passing the XHR that carried the AJAX call and the evaluated X-JSON header.

Our sample did not process the XML response in any interesting way. We just dumped the XML in the
textarea. A typical usage of the response would probably find the desired information inside the XML and
update some page elements, or maybe even some sort of XSLT transformation to produce HTML in the
page.

There's also another form of event callback handling available. If you have code that should always be
executed for a particular event, regardless of which AJAX call caused it to happen, then you can use the
new Ajax.Responders object.

Let's suppose you want to show some visual indication that an AJAX call is in progress, like a spinning
icon or something of that nature. You can use two global event handlers to help you, one to show the icon
when the first call starts and another one to hide the icon when the last one finishes. See example below.

<script type="text/javascript">
var myGlobalHandlers = {
onCreate: function () {
Element.show('systemWorking');
},

onComplete: function () {
if(Ajax.activeRequestCount === 0){
Element.hide('systemWorking');
}
}
};

Ajax.Responders.register(myGlobalHandlers);
</script>
<div id='systemWorking'><img src='spinner.gif'>Loading...</div>

For more complete explanations, see the Ajax.Request reference and the options reference.

Exercise: AJAX Search


Duration: 30 to 45 minutes.

We will use Prototype AJAX support to call a server-side search service and display the results without
ever reloading our page.

1. Create a method WEBUCATOR.doSearch(text)


2. Call that method from the Go button's click
3. Use the textbox's value as the search term (the argument to the method)
4. Make the doSearch method perform an AJAX call to ../Common/search.php passing the search
term as the "q" posted parameter.
5. Print the response returned form that method (you can use debugWrite or alert)

Don't get too worried about the PHP file that we use. Just treat it as some generic URL that will find news
items that contain a given word from a database. The search.php script will simply read the value posted in
the q parameter and look into the cnn.xml file looking for items that contain that value in the description
element.

Once the page is ready, you should be able to type a word in the input field and click the Go! button to see
all the stories that contain that word be listed.

Code Sample: PrototypeJS/Exercises/ajax-search.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title> Ajax Request </title>
<script src="../../Libraries/prototype.js" type="text/javascript"></script>
<script src="../../Libraries/DebugHelp.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
//add the debud panel at the bottom of the page
Event.observe(window, 'load', function () {insertDebugPanel();} );
</script>
<script type="text/javascript">
var WEBUCATOR = { };
/*
The file ..\Common\cnn.xml contains an old copy
of the xml from the URL:
http://rss.cnn.com/rss/cnn_topstories.rss
If you wish, you can get a newer version of the xml and
update that file.

1 - Create a method WEBUCATOR.doSearch(text)


2 - Call that method from the Go button's click
3 - Use the textbox's value as the search term (the argument to the method)
4 - Make the doSearch method perform an AJAX call to ../Common/search.php
passing the search term as the "q" posted parameter.
5 - Print the response returned form that method (you can use debugWrite or alert)
*/

WEBUCATOR.onload = function () {

};

Event.observe(window, 'load', WEBUCATOR.onload );

</script>
<form action="#">
<input type="text" name="searchTerm" value="" id="searchTerm"/>
<input type="button" name="goButton" value="Go!" id="goButton"/>
</form>
</body>
</html>

Code Sample: PrototypeJS/Common/search.php


<?php
$doc = new DOMDocument();
$doc->load( 'cnn.xml' );

$searchTerm = $_POST['q'];

$xpath = new Domxpath($doc);


$newsItems = $xpath->query( "//item" );
foreach( $newsItems as $item )
{

$desc = $item->getElementsByTagName( "description" );


$content = $desc->item(0)->nodeValue;
$pos1 = stripos($content, $searchTerm);

if ($pos1 !== false) {


$title = $item->getElementsByTagName( "title" )->item(0)->nodeValue;
$link = $item->getElementsByTagName( "link" )->item(0)->nodeValue;
echo "<li><strong><a href=\"$link\">$title</a></strong><br/>$content</li>";
}

?>
Where is the solution?

Using the Ajax.Updater class


If you have a server endpoint that can return information already formatted in HTML, the library makes life
even easier for you with the Ajax.Updater class. With it you just inform which element should be filled
with the HTML returned from the AJAX call. An example speaks better than I can write.

<script type="text/javascript">
function getHTML() {
var url = 'http://yourserver/app/getSomeHTML';
var pars = 'someParameter=ABC';

var myAjax = new Ajax.Updater(


'placeholder',
url,
{
method: 'get',
parameters: pars
});

}
</script>
<input type="button" value="GetHtml" onclick="getHTML();"/>
<div id="placeholder"></div>

As you can see, the code is very similar to the previous example, with the exclusion of the onComplete
function and the element id being passed in the constructor. Let's change the code a little bit to illustrate
how it is possible to handle server errors on the client.

We will add more options to the call, specifying a function to capture error conditions. This is done using
the onFailure option. We will also specify that the placeholder only gets populated in case of a successful
operation. To achieve this we will change the first parameter from a simple element id to an object with
two properties, success (to be used when everything goes OK) and failure (to be used when things go bad.)
We will not be using the failure property in our example, just the reportError function in the onFailure
option.

<script type="text/javascript">
function getHTML() {
var url = 'http://yourserver/app/getSomeHTML';
var pars = 'someParameter=ABC';

var myAjax = new Ajax.Updater(


{success: 'placeholder'},
url,
{
method: 'get',
parameters: pars,
onFailure: reportError
});

function reportError(response) {
alert('Sorry. There was an error.');
}
</script>
<input type="button" value="GetHtml" onclick="getHTML();"/>
<div id="placeholder"></div>

Exercise: AJAX Search


Duration: 30 to 45 minutes.

We will use Prototype AJAX support to call a server-side search service and display the results without
ever reloading our page.

1. Create a method WEBUCATOR.doSearch(text)


2. Call that method from the Go button's click
3. Use the textbox's value as the search term (the argument to the method)
4. Using the Ajax.pdater class, make the doSearch method perform an AJAX call to
../Common/search.php passing the search term as the "q" querystring parameter.
5. The returned HTML should automatically uplade the resultList element.

The search.php script is the same from the previous exercise. You may have noticed that it returns a series
of li elements. We will use these elements directly inside the resultList element.

Code Sample: PrototypeJS/Exercises/ajax-updater.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
<title> Ajax Updater </title>
<script src="../../Libraries/prototype.js" type="text/javascript"></script>
<script src="../../Libraries/DebugHelp.js" type="text/javascript"></script>
<style type="text/css" media="screen">
#resultList
{
background-color:#ddd;
width:500px;
}
#resultList li
{
background-color:#ddf;
padding:4px;
border:1px solid #33a;
margin:4px;
}
</style>
</head>
<body>
<script type="text/javascript">
//add the debud panel at the bottom of the page
Event.observe(window, 'load', function () {insertDebugPanel();} );
</script>
<script type="text/javascript">
var WEBUCATOR = { };
/*
The file ..\Common\cnn.xml contains an old copy
of the xml from the URL:
http://rss.cnn.com/rss/cnn_topstories.rss
If you wish, you can get a newer version of the xml and
update that file.

1 - Create a method WEBUCATOR.doSearch(text)


2 - Call that method from the Go button's click
3 - Use the textbox's value as the search term (the argument to the method)
4 - Using the Ajax.pdater class, make the doSearch method perform an AJAX call
to ../Common/search.php passing the search term as the "q" querystring parameter.
5 - The returned HTML should automatically uplade the resultList element
*/

WEBUCATOR.onload = function () {

};

Event.observe(window, 'load', WEBUCATOR.onload );

</script>
<form action="#">
<input type="text" name="searchTerm" value="" id="searchTerm"/>
<input type="button" name="goButton" value="Go!" id="goButton" />
</form>
<h2>Results:</h2>
<ol id="resultList">
<li><strong>test:</strong><br/>
test test test test test
test test test test test
test test test test test
test test test test test
test test test test test
test test test test test
</li>
<li><strong>test:</strong><br/>
test test test test test
test test test test test
test test test test test
test test test test test
test test test test test
test test test test test
</li>
</ol>
</body>
</html>
Where is the solution?

If your server logic returns JavaScript code along with HTML markup, the Ajax.Updater object can
evaluate that JavaScript code. To get the object to treat the response as JavaScript, you simply add
evalScripts: true; to the list of properties in the last argument of the object constructor. But there's a caveat.
Those script blocks will not be added to the page's script. As the option name evalScripts suggests, the
scripts will be evaluated. What's the difference, you may ask? Lets assume the requested URL returns
something like this:
<script language="javascript" type="text/javascript">
function sayHi() {
alert('Hi');
}
</script>
<input type="button" value="Click Me" onclick="sayHi();"/>

In case you've tried it before, you know it doesn't work. The reason is that the script block will be
evaluated, and evaluating a script like the above will not create a function named sayHi. It will do nothing.
To create this function we need to change our script to create the function. See below.

<script language="javascript" type="text/javascript">


sayHi = function () {
alert('Hi');
};
</script>
<input type="button" value="Click Me" onclick="sayHi();"/>

Note that in the previous example we did not use the var keyword to declare the variable. Doing so would
have created a function object that would be local to the script block (at least in IE). Without the var
keyword the function object is scoped to the window, which is our intent.

For more complete explanations, see the Ajax.Updater reference and the options reference.

What are all those "?" and squares?


So you went and wrote some quick test scripts to update your pages using the Ajax.Updater object and it all
worked fine. Life was good until you ran your scripts against real data. All of a sudden the updated text was
displayed with question marks or unprintable character symbols where the non-English characters should
be.

Your first suspect is Prototype, Of course, it seemed too easy to be true. But don't blame the library just yet.
Ask yourself how much you really understand character encoding, code pages, and how the browser deals
with it. If you have a positive answer then I bet you are on your way to fix the problem. If you are among
the other 80% (another useless, imprecise author's estimate) of web developers that take character encoding
for granted, keep reading.

I won't pretend to be an authority on the topic, much less give you a complete explanation of how this is
best handled. Instead you go straight to the solution that I use and provide hints on how this could be fixed
in your own scenario.

Simply put, the solution revolves around the following statement: Serve what the browser is expecting you
to serve. If we are going to update the page with text that contains Unicode/UTF-8 characters then we
better make the browser aware of that.

Let's start with the simple case when you are just updating the page with text from a static HTML file that
resides on your server. When you created that file, depending on which text editor you employed, it is very
possible that the file was saved in ANSI (or better said, non-Unicode) format. This is the default for many
text editors, especially source code editors, because the file size will be smaller and it's rather unusual to
edit source code with Unicode characters in it.

Suppose you have the following file named static-content.html on your server. You saved this file saved in
ANSI format.

<div>
Hi there, José. Yo no hablo español.
</div>

Your main page updates itself using something like the snippet below.

<script type="text/javascript">
function updateWithFile() {
var url = 'static-content.html';
var pars = '';
var myAjax = new Ajax.Updater(
'placeholder', url,
{method: 'get', parameters: pars});
}
</script>
<div id="placeholder">(this will be replaced)</div>
<input id="btn" value="Test With Static File"
onclick="updateWithFile();" type="button"/>

When you click the button the static file is retrieved but the non-English characters are replaced by question
marks or some other symbol. The displayed text will look similar to "Hi there, Jos?. Yo no hablo espa?ol."
or "Hi there, Jos?Yo no hablo espa?", depending on your browser.

In this case, the solution is straightforward, simply save the static file in an appropriate format. Let's save it
in UTF-8 and run the script again (any decent text editor will have an option in the Save As dialog.) You
should now see the correct text (if not, your browser may have cached the old version, try using a different
file name.)

If the HTML that you are serving is not static, if it is being dynamically generated by some application
framework (like ASP.NET, PHP, or even Perl,) make sure the code that generates this HTML is producing
the text in the appropriate encoding and code page, and include in the HTTP response headers one header
that informs this. Each platform has a different way to achieve this, but they are very similar.

For example, in ASP.NET you can set this globally in your web.config file and the default configuration is
good enough to avoid this problem in the first place. You should already have the following section in your
web.config.

<globalization requestEncoding="utf-8" responseEncoding="utf-8" />

In classic ASP 3.0 you can fix this problem using the following code.

Response.CodePage = 65001
Response.CharSet = "utf-8"

In PHP the syntax to add the response header looks like this.

<?php header('Content-Type: text/html; charset=utf-8'); ?>

In any case, your ultimate goal is to have the following HTTP header sent with your response.

Content-Type: text/html; charset=utf-8

We used UTF-8 in our examples above, but if you need a different setting you can easily change.

Enumerating... Geez! Wow! Wahoo!


We are all familiar with for loops. You know, create yourself an array, populate it with elements of the
same kind, create a loop control structure (for, foreach, while, repeat, etc,) access each element
sequentially, by its numeric index, and do something with the element.

When you come to think about it, almost every time you have an array in your code it means that you'll be
using that array in a loop sooner or later. Wouldn't it be nice if the array objects had more functionality to
deal with these iterations? Yes, it would, and many programming languages provide such functionality in
their arrays or equivalent structures (like collections and lists.)

Well, it turns out that Prototype gives us the Enumerable object, which implements a plethora of tricks for
us to use when dealing with iterable data. The Prototype library goes one step further and extends the Array
class with all the methods of Enumerable.

Loops, Ruby-style
In standard javascript, if you wanted to sequentially display the elements of an array, you could very well
write something like this.

<script type="text/javascript">
function showList() {
var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Maggie'];
for (i=0; i<simpsons.length; i++) {
alert(simpsons[i]);
}
}
</script>
<input type="button" value="Show List" onclick="showList();" />

With our new best friend, Prototype, we can rewrite this loop like this.

function showList() {
var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Maggie'];
simpsons.each( function (familyMember) {
alert(familyMember);
});
}

You are probably thinking "big freaking deal...just a weird syntax for the same old thing." Well, in the
above example, yes, there's nothing too earth shattering going on. After all, there's not much to be changed
in such a drop-dead-simple example. But keep reading, nonetheless.

Before we move on. Do you see this function that is being passed as an argument to the each method? Let's
start referring to it as an iterator function.

Your arrays on steroids


Like we mentioned above, it's very common for all the elements in your array to be of the same kind, with
the same properties and methods. Let's see how we can take advantage of iterator functions with our new
souped-up arrays.

Here's how to find an element according to criteria.

<script type="text/javascript">
function findEmployeeById(emp_id) {
var listBox = $('lstEmployees')
var options = listBox.getElementsByTagName('option');
options = $A(options);
var opt = options.find( function (employee) {
return
(employee.value === emp_id)
;
});
alert(opt.innerHTML); //displays the employee name
}
</script>

<select id="lstEmployees" size="10" >


<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Find Laura" onclick="findEmployeeById(8);" />

Now let's kick it up another notch. See how we can filter out items in arrays, and then retrieve just a desired
member from each element.

<script type="text/javascript">
function showLocalLinks(paragraph) {
paragraph = $(paragraph);
var links = $A(paragraph.getElementsByTagName('a'));
//find links that do not start with 'http'
var localLinks = links.findAll( function (link) {
//we'll just assume for now that external links
// do not have a '#' in their url
return link.href.indexOf('#') >= 0;
});
//now the link texts
var texts = localLinks.pluck('innerHTML');
//get them in a single string
var result = texts.inspect();
alert(result);
}

</script>
<p id="someText">
This <a href="http://othersite.com/page.html">text</a> has
a <a href="#localAnchor">lot</a> of
<a href="#otherAnchor">links</a>. Some are
<a href="http://wherever.com/page.html">external</a>
and some are <a href="#someAnchor">local</a>
</p>
<input type="button" value="Find Local Links" onclick="showLocalLinks('someText');"/>

It takes just a little bit of practice to get completely addicted to this syntax. Take a look at the Enumerable
and Array references for all the available functions.

Handling Events
Events are a big part of most UI programming. On the web this part has been historically difficult because
of the different ways browser makers chose to implement it.

If you have written cross-browser event handling before, you are probably familiar with all the forks in you
code to support Mozilla and IE. Prototype helps us by providing a uniform syntax for taking care of that.

We mentioned unobtrusive JavaScript in a previous lesson and Prototype offers great support for that
through its event subscription infrastructure.
Observing Events
The onXXXXXX properties of the DOM elements is a great source of contention for event handling code.
Traditionally you would see scripts that, for example, run when the page loads by changing the body
element's onload property.

window.onload = function(){alert('loaded');};
// or in the tag itsef:
<body onload="alert('loaded');">

The obvious problem here is that if another script also needs to know about that load event, it's possible
(and sadly often common) that this script would overwrite the original value of the onload property,
causing the page to misbehave.

The way Prototype addresses this is by using either the DOM standard for event subscription (when
supported by the browser) or browser specific code (mostly IE) to add or remove listeners to these events.
Prototype calls these listeners observers.

Observers do not overwrite each other. They are just appended to a list of observers for each individual
element event. The previous code would be written differently with Prototype.

Event.observe(window, 'load', function (evt) { alert('loaded'); } );


//to unsubscribe from the event later, the code is:
Event.stopObserving(window, 'load');

To make it even easier, the event subscription mechanism is added to the DOM elements, simplifying the
syntax even further.

$('myElement').observe('click', function (evt) {


alert('myElement was clicked');
} );

DOM Loaded
To support unobtrusive JavaScript even more, Prototype extends the document object with an important
event called dom:loaded. This event is fired when all the elements in the document are loaded in the DOM
and ready to be programmed against. Maybe some images or CSS didn't finish loading yet, but the DOM is
good to go.

When the DOM is loaded is the right time to add the observers to the other elements.

document.observe('dom:loaded' function () {
$('panelRight').observe('click', function (evt) {
collapseRightPanel();
});

$('userNameField').observe('keypress', function (evt) {


submitOnEnterKey();
});
});

Event Information
You may have noticed the evt parameter that is being passed for the observer functions in the previous
examples. This parameter carries important information about the event itself. Things like what element
was the source of the event, the mouse pointer coordinates and which mouse button was clicked. The
complete list of properties and methods of this object can be found at the Event object reference.

Official Site
Before we start using the library reference below, it's important to note that Prototype is a project on the
move and any reference material in print is bound to quickly become obsolete.

To get the most up-to-date documentation of the library we should always consult Prototype's official site
at http://www.prototypejs.org.

If you like to always have the latest possible version of the library or if you're interested in tracking the
library development as it happens, you can visit the project development site or even the current source
code.

When you have questions and you need to ask for help, a good place to go is the mailing list. A lot of very
knowledgeable Prototype developers hang out in this list and may be able to help you.

Reference for Prototype


Extensions to the JavaScript objects
One of the ways the Prototype library adds functionality is by extending the existing JavaScript objects.

Extensions for the Object object


Method Kind Arguments Description
destination: any
extend(destination, Provides a way to implement inheritance by copying all
static object, source: any
source) properties and methods from source to destination.
object
Returns a human-readable string representation of
targetObj: any
inspect(targetObj) static targetObj. It defaults to the return value of toString if the
object
given object does not define an inspect instance method.
targetObj: any Returns an Array with the names of all the properties and
keys(targetObj) static
object methods of given object.
targetObj: any Returns a Array with the values of all the properties and
values(targetObj) static
object methods of given object.
targetObj: any
clone(targetObj) static Returns a shallow copy of targetObj.
object
Extensions for the Number objects
Method Kind Arguments Description
Returns the hexadecimal representation of the number.
toColorPart() instance (none) Useful when converting the RGB components of a
color into its HTML/CSS representation.
Returns the next number. This function is used in
succ() instance (none)
scenarios that involve iterations.
iterator: a function object
Calls the iterator function repeatedly passing the
times(iterator) instance conforming to
current index in the index argument.
Function(index)
The following sample will display alert message boxes from 0 to 9.

<script type="text/javascript">
function demoTimes() {
var n = 10;
n.times( function (index) {
alert(index);
});
/***************************
* you could have also used:
* (10).times( .... );
***************************/
}
</script>
<input type="button" value="Test Number.times()" onclick="demoTimes();"/>
Extensions for the Function objects
Method Kind Arguments Description
object: the Returns an instance of the function pre-bound to
bind(object [, arg1 [, arg2 object that the function(=method) owner object. The returned
instance
[...]]]) owns the function will use the same arguments as the
method original one (arg1, arg2, ... etc).
Returns an instance of the function pre-bound to
object: the
the function(=method) owner object. The returned
bindAsEventListener(object [, object that
instance function will have the current event object as its
arg1 [, arg2 [...]]]) owns the
first argument followed optionally any other
method
arguments passed after the object argument.

Let's see one of these extensions in action.

<input type="checkbox" id="myChk" value="1"/> Test?


<script type="text/javascript">
//declaring the class
var CheckboxWatcher = Class.create();

//defining the rest of the class implementation


CheckboxWatcher.prototype = {

initialize: function (chkBox, message) {


this.chkBox = $(chkBox);
this.message = message;
//assigning our method to the event

this.chkBox.onclick =
this.showMessage.bindAsEventListener(this, ' from checkbox');

},

showMessage: function (evt, extraInfo) {


alert(this.message + ' (' + evt.type + ')' + extraInfo);
}
};

var watcher = new CheckboxWatcher('myChk', 'Changed');


</script>
Extensions for the String objects
Method Kind Arguments Description
Converts a hyphen-delimited-string into a
camelCaseString. This function is useful when
camelize() instance (none)
writing code that deals with style properties, for
example.
Extensions for the String objects
Method Kind Arguments Description
capitalize() instance (none) Converts the first character to upper case.
dasherize() instance (none) Replaces underscores '_' with dashes '-'.
Returns the string with any HTML markup
escapeHTML() instance (none)
characters properly escaped
Evaluates each <script /> block found in the
evalScripts() instance (none)
string.
Returns an Array object containing all the <script
extractScripts() instance (none)
/> blocks found in the string.
Returns a string that results from finding (or
matching) the pattern string (or regular
expression) in the current string and replacing it
pattern: string or regular with the replacement string or the result of calling
expression being searched. the replacement function passing an array with
gsub(pattern, replacement: simple string, the strings that matched the pattern, including
instance
replacement) template string, or eventual regular expression groupings. When the
Function(strings[]) to replacement is a string, it can contain special
produce the replacements. templating tokens like #{n}, where n is the index
of a grouping in the regular expession. #{0} will
be replaced by the entire match, #{1} the first
grouping, #{2} the second, and so on.
parseQuery() instance (none) Same as toQueryParams().
Provides a way to iterate over matched patterns in
the string and operate on them. The pattern
pattern: string or regular
argument can be a string or a RegExp but a
expression being searched.
scan(pattern, RegExp is evidently more useful. Similarly, the
instance replacement:
replacement) replacement argument can be a string or a
Function(strings[]) to
function but it probably only makes sense to pass
iterate over the matches.
in a function to be able to produce anything
useful.
Returns the string without any leading or trailing
strip() instance (none)
white spaces.
Returns the string with any <script /> blocks
stripScripts() instance (none)
removed
Returns the string with any HTML or XML tags
stripTags() instance (none)
removed
pattern: string or regular
expression being searched.
replacement: string, or
sub(pattern, Very similar to gsub but only performs a limited
Function(strings[]) to
replacement [, instance number of replacements, specified by the count
produce the replacements.
count]) parameter.
count: number or
replacements to perform -
defaults to 1.
toArray() instance (none) Splits the string into an Array of its characters.
Splits a querystring into an associative Array
toQueryParams() instance (none)
indexed by parameter name (more like a hash).
length: maximum length of Used to produce a string of a known maximum
truncate(length [,
instance the resulting string. length. In case the string needs to be truncated to
truncation])
truncation: string used to maintain the maximum length, the text given in
Extensions for the String objects
Method Kind Arguments Description
replace the last characters the truncation argument is used to replace the last
of the resulting string - few characters. (e.g.: var s='123456790';
defaults to '...' alert(s.truncate(5)); //displays '12...' )
Converts a CamelizedStringValue into a
uderscore_formatted_string. (e.g.: var
s='Namespace::MyClass123';
underscore() instance (none) alert(s.underscore()); //displays
'namespace/my_class123' ). This function seems
to be directly target at supporting Ruby on Rails
functionality.
unescapeHTML() instance (none) The reverse of escapeHTML()

Extensions for the Array objects


To start off, Array extends Enumerable, so all the handy methods defined in the Enumerable object are
available. Besides that, the methods listed below are also implemented.

Extensions for the Array objects


Method Kind Arguments Description
clear() instance (none) Empties the array and returns itself.
Returns the array without the elements that are
compact() instance (none) null or undefined. This method does not change
the array itself
first() instance (none) Returns the first element of the array.
Returns a flat, one-dimensional version of the
array. This flattening happens by finding each of
flatten() instance (none) the array's elements that are also arrays and
including their elements in the returned array,
recursively.
Returns the zero-based position of the given
value: what you are
indexOf(value) instance value if it is found in the array. Returns -1 if
looking for.
value is not found.
Overridden to return a nicely formatted string
inspect() instance (none)
representation of the array with its elements.
last() instance (none) Returns the last element of the array.
applyToSelf: indicates Returns the array in reverse sequence. If no
if the array itself argument is given or if the argument is true the
reverse([applyToSelf]) instance
should also be array itself will be changed. Otherwise it will
reversed. remain unchanged.
Returns the first element and removes it from
shift() instance (none)
the array, reducing the array's length by 1.
value1 ... valueN: Returns the array excluding the elements that
without(value1 [, value2
instance values to be excluded are included in the list of arguments. This
[, .. valueN]])
if present in the array. method does not change the array itself.

Let's see some of these methods in action.

<script type="text/javascript">
var A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
alert(A.inspect()); // "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']"
var B = A.without('e','f');
alert(B.inspect()); // "['a', 'b', 'c', 'd', 'g', 'h']"
alert(A.inspect()); // did not change A: "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']"
A.push(null);
A.push('x');
A.push(null);
A.push('y');
alert(A.inspect()); // "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', null, 'x', null, 'y']"
A = A.compact();
alert(A.inspect()); // "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'x', 'y']"
var e = A.shift();
alert(e); // "a"
alert(A.inspect()); // "['b', 'c', 'd', 'e', 'f', 'g', 'h', 'x', 'y']"
alert(A.indexOf('c')); // 1
alert(A.first()); // 'b'
alert(A.last()); // 'y'
A.clear();
alert(A.inspect()); // "[]"
A = ['a', 'b', 'c'];
B = A.reverse(false);
alert(B.inspect()); // "['c', 'b', 'a']"
alert(A.inspect()); // A left untouched: "['a', 'b', 'c']"
A.reverse(true);
alert(A.inspect()); // "['c', 'b', 'a']"
A = ['a', 'b', ['c1','c2','c3'] , 'd', ['e1','e2'] ];
B = A.flatten();
alert(B.inspect()); // "['a','b','c1','c2','c3','d','e1','e2']"
alert(A.inspect()); // unchanged: "['a','b',['c1','c2','c3'],'d',['e1','e2']]"
</script>
Extensions for the document DOM object
Method Kind Arguments Description
className: name of a CSS Returns all the elements
class associated with the that are associated with the
getElementsByClassName(className elements, parentElement: given CSS class name. If no
instance
[, parentElement]) object or id of the element parentElement id given, the
that contains the elements entire document body will
being retrieved. be searched.
Extensions for the Event object
Property Type Description
KEY_BACKSPACE Number 8: Constant. Code for the Backspace key.
KEY_TAB Number 9: Constant. Code for the Tab key.
KEY_RETURN Number 13: Constant. Code for the Return key.
KEY_ESC Number 27: Constant. Code for the Esc key.
KEY_LEFT Number 37: Constant. Code for the Left arrow key.
KEY_UP Number 38: Constant. Code for the Up arrow key.
KEY_RIGHT Number 39: Constant. Code for the Right arrow key.
KEY_DOWN Number 40: Constant. Code for the Down arrow key.
KEY_DELETE Number 46: Constant. Code for the Delete key.
List of cached observers. Part of the internal implementation details of the
observers: Array
object.
Method Kind Arguments Description
Returns element that originated the
element(event) static event: an Event object
event.
event: an Event object, Traverses the DOM tree upwards,
findElement(event, tagName) static
tagName: name of the searching for the first element with the
Method Kind Arguments Description
desired tag. given tag name, starting from the
element that originated the event.
Returns true if the left mouse button
isLeftClick(event) static event: an Event object
was clicked.
Returns true if the middle mouse button
isMiddleClick(event) static event: an Event object
was clicked.
Returns true if the right mouse button
isRightClick(event) static event: an Event object
was clicked.
Returns the x coordinate of the mouse
pointerX(event) static event: an Event object
pointer on the page.
Returns the y coordinate of the mouse
pointerY(event) static event: an Event object
pointer on the page.
Use this function to abort the default
stop(event) static event: an Event object behavior of an event and to suspend its
propagation.
element: object or id,
name: event name (like
observe(element, name, Adds an event handler function to an
static 'click', 'load', etc),
observer) event.
observer: Function(evt) to
handle the event.
Removes an event handler from the
element: object or id, event. If the observer isn't passed, it
stopObserving(element [, name name: event name (like will unregister all observers for the
static
[, observer]]) 'click'), observer: function given event name. If the event name
that is handling the event. isn't passed it will unregister all
observers for the element.
_observeAndCache(element,
static  Private method, do not worry about it.
name, observer, useCapture)
Private method, do not worry about it.
unloadCache() static (none) Clears all cached observers from
memory.

Let's see how to use this object to add an event handler to the load event of the window object.

<script type="text/javascript">
Event.observe(window, 'load', page_loaded, false);

function page_loaded(evt) {
Event.observe('parent_node', 'click', item_clicked, false);
}

function item_clicked(evt) {
var child = Event.element(evt);
alert('The child node with id=' + child.id + ' was clicked');
Event.stop(evt); //avoid another call related to 'parent_node' itself
}
</script>
...
<div id="parent_node">
<div id="child1">First</div>
<div id="child2">Second</div>
<div id="child3">Third</div>
</div>

New objects and classes defined by Prototype


Another way the library helps you is by providing many objects that implement both support for object
oriented designs and common functionality in general.

The PeriodicalExecuter object


This object provides the logic for calling a given function repeatedly, at a given interval, using a timer.

Method Kind Arguments Description


callback: a function that will be passed
Creates one instance of this object
[ctor](callback, the PeriodcalExecuter object itself as the
constructor that will call the function
interval) only argument, interval: number of
repeatedly.
seconds
registerCallback() instance (none) Resets the timer.
Cancels the timer, avoiding the
stop() instance (none)
execution of the callback.
This method is what will be
called by the timer. It, in turn,
onTimerEvent() instance (none)
will invoke the callback method
passing the object itself.
Property Type Description
The function to be called. objExecuter: the PeriodcalExecuter
callback Function(objExecuter)
making the call.
A handle to the underlying timer object responsible for
timer Timer
repeatedly invoking the callback method
frequency Number This is actually the interval in seconds
currentlyExecuting Boolean Indicates if the callback is underway.

The Prototype object


The Prototype object does not have any important role, other than declaring the version of the library being
used.

Property Type Description


Version String The version of the library
emptyFunction Function() An empty function object
K Function(obj) A function object that just echoes back the given parameter.
ScriptFragment String A regular expression to identify scripts

The Enumerable object


The Enumerable object allows one to write more elegant code to iterate items in a list-like structure.

Many other objects extend the Enumerable object to leverage its useful interface.

Method Kind Arguments Description


iterator: a function object Calls the given iterator function passing each
each(iterator) instance conforming to element in the list in the first argument and
Function(value, index) the index of the element in the second
Method Kind Arguments Description
argument
This function is a way to test the entire
collection of values using a given function. all
will return true only if the iterator function
iterator: a function object
returns a value that resolves to true for all the
conforming to
all([iterator]) instance elements. It will return false otherwise. If no
Function(value, index),
iterator is given, then the test will be if the
optional.
element itself resolves to true. You can
simply read it as "check if all elements pass
the test."
This function is a way to test the entire
collection of values using a given function.
any will return true if the iterator function
iterator: a function object
returns a value that resolves to true for at least
conforming to
any([iterator]) instance one of the elements. It will return false
Function(value, index),
otherwise. If no iterator is given, then the test
optional.
will be if the element itself resolves to true.
You can simply read it as "check if any
element passes the test."
Calls the iterator function for each element in
iterator: a function object
the collection and returns each result in an
collect(iterator) instance conforming to
Array, one result element for each element in
Function(value, index)
the collection, in the same sequence.
Calls the iterator function for each element in
iterator: a function object the collection and returns the first element
detect(iterator) instance conforming to that caused the iterator function to return true
Function(value, index) (or, more precisely, not-false.) If no element
returns true, then detect returns null.
entries() instance (none) Same as toArray().
iterator: a function object
find(iterator) instance conforming to Same as detect().
Function(value, index)
Calls the iterator function for each element in
iterator: a function object the collection and returns an Array with all
findAll(iterator) instance conforming to the elements that caused the iterator function
Function(value, index) to return a value that resolves to true. This
function is the opposite of reject().
Tests the string value of each element in the
collection against the pattern regular
pattern: a RegExp object
expression . The function will return an Array
used to match the elements,
grep(pattern [, containing all the elements that matched the
instance iterator: a function object
iterator]) regular expression. If the iterator function is
conforming to
given, then the Array will contain the result
Function(value, index)
of calling the iterator with each element that
was a match.
Tries to find the given object in the
include(obj) instance obj: any object collection. Returns true if the object is found,
false otherwise.
Returns the collection broken in groups
number: number of items
inGroupsOf(number, containing as many items as specified by the
instance per group, fillWith: value
fillWith) first argument. If the quantity of items in the
used to fill empty spots
initial collection is not divisible by the
Method Kind Arguments Description
number in the first argument, the resulting
empty items at the end of the last group will
be filled with null or with the value of the
second argument, if provided. Quick
example: ['a','b','c','d'].inGroupsOf(3,'?')
creates [ ['a','b','c'] , ['d','?','?'] ]
Combines all the elements of the collection
initialValue: any object to
using the iterator function. The iterator is
be used as the initial value,
called passing the result of the previous
inject(initialValue, iterator: a function object
instance iteration in the accumulator argument. The
iterator) conforming to
first iteration gets initialValue in the
Function(accumulator,
accumulator argument. The last result is the
value, index)
final return value.
methodName: name of the
method that will be called Calls the method specified by methodName
invoke(methodName [, in each element, in each element of the collection, passing any
instance
arg1 [, arg2 [...]]]) arg1..argN: arguments that given arguments (arg1 to argN), and returns
will be passed in the the results in an Array object.
method invocation.
iterator: a function object
map(iterator) instance conforming to Same as collect().
Function(value, index)
Returns the element with the greatest value in
iterator: a function object
the collection or the greatest result of calling
max([iterator]) instance conforming to
the iterator for each element in the collection,
Function(value, index)
if an iterator is given.
member(obj) instance obj: any object Same as include().
Returns the element with the lowest value in
iterator: a function object
the collection or the lowest result of calling
min([iterator]) instance conforming to
the iterator for each element in the collection,
Function(value, index)
if an iterator is given.
Returns an Array containing two other arrays.
The first array will contain all the elements
that caused the iterator function to return true
iterator: a function object
and the second array will contain the
partition([iterator]) instance conforming to
remaining elements. If the iterator is not
Function(value, index)
given, then the first array will contain the
elements that resolve to true and the other
array will contain the remaining elements.
propertyName name of the
Retrieves the value to the property specified
property that will be read
by propertyName in each element of the
pluck(propertyName) instance from each element. This
collection and returns the results in an Array
can also contain the index
object.
of the element
Calls the iterator function for each element in
iterator: a function object the collection and returns an Array with all
reject(iterator) instance conforming to the elements that caused the iterator function
Function(value, index) to return a value that resolves to false. This
function is the opposite of findAll().
iterator: a function object
select(iterator) instance conforming to Same as findAll().
Function(value, index)
Method Kind Arguments Description
iterator: a function object Returns an Array with all the elements sorted
sortBy(iterator) instance conforming to according to the result the iterator function
Function(value, index) call.
Returns an Array with all the elements of the
toArray() instance (none)
collection.
Merges each given collection with the current
collection. The merge operation returns a new
array with the same number of elements as
the current collection and each element is an
collection1 .. collectionN:
zip(collection1[, array (let's call them sub-arrays) of the
enumerations that will be
collection2 [, ... elements with the same index from each of
instance merged, transform: a
collectionN the merged collections. If the transform
function object conforming
[,transform]]]) function is given, then each sub-array will be
to Function(value, index)
transformed by this function before being
returned. Quick example: [1,2,3].zip([4,5,6],
[7,8,9]).inspect() returns "[
[1,4,7],[2,5,8],[3,6,9] ]"

The Hash object


The Hash object implements a hash structure, i.e. a collection of Key:Value pairs.

Each item in a Hash object is an array with two elements: first the key then the value. Each item also has
two properties: key and value, which are pretty self-explanatory.

Method Kind Arguments Description


keys() instance (none) Returns an Array with the keys of all items.
values() instance (none) Returns an Array with the values of all items.
otherHash: Combines the hash with the other hash passed in and returns
merge(otherHash) instance
Hash object the new resulting hash.
Returns all the items of the hash in a string formatted like a
toQueryString() instance (none)
query string, e.g. 'key1=v1&key2=v2&key3=v3'
Overridden to return a nicely formatted string representation
inspect() instance (none)
of the hash with its key:value pairs.

The ObjectRange class


Inherits from Enumerable

Represents a range of values, with upper and lower bounds.

Property Type Kind Description


start (any) instance The lower bound of the range
end (any) instance The upper bound of the range
exclusive Boolean instance Determines if the boundaries themselves are part of the range.
Method Kind Arguments Description
[ctor](start, end, start: the lower bound, end: Creates one range object, spanning from
constructor
exclusive) the upper bound, exclusive: start to end. It is important to note that
Method Kind Arguments Description
include the bounds in the start and end have to be objects of the
range? same type and they must have a succ()
method.
searchedValue: value that Checks if the given value is part of the
include(searchedValue) instance
we are looking for range. Returns true or false.

The Class object


The Class object is used when declaring the other classes in the library. Using this object when declaring a
class causes the to new class to support an initialize() method, which serves as the constructor.

See the sample below.

//declaring the class


var MySampleClass = Class.create();

//defining the rest of the class implementation


MySampleClass.prototype = {

initialize: function (message) {


this.message = message;
},

showMessage: function (ajaxResponse) {


alert(this.message);
}
};

//now, let's instantiate and use one object


var myTalker = new MySampleClass('hi there.');
myTalker.showMessage(); //displays alert
Method Kind Arguments Description
create(*) instance (any) Defines a constructor for a new class

The Ajax object


This object serves as the root and namespace for many other classes that provide AJAX functionality.

Property Type Kind Description


activeRequestCount Number instance The number of AJAX requests in progress.
Method Kind Arguments Description
getTransport() instance (none) Returns a new XMLHttpRequest object

The Ajax.Responders object


Inherits from Enumerable

This object maintains a list of objects that will be called when Ajax-related events occur. You can use this
object, for example, if you want to hook up a global exception handler for AJAX operations.

Property Type Kind Description


responders Array instance The list of objects registered for AJAX events notifications.
Method Kind Arguments Description
The object passed in the
responderToAdd argument should
contain methods named like the
AJAX events (e.g. onCreate,
responderToAdd: object with onComplete, onException, etc.)
register(responderToAdd) instance
methods that will be called. When the corresponding event
occurs all the registered objects
that contain a method with the
appropriate name will have that
method called.
The object passed in the
responderToRemove: object responderToRemove argument
unregister(responderToRemove) instance
to be removed from the list. will be removed from the list of
registered objects.
Runs through the list of registered
objects looking for the ones that
have the method determined in the
callback: name of the AJAX
callback argument. Then each of
event being reported, request:
these methods is called passing
the Ajax.Request object
the other 3 arguments. If the
responsible for the event,
AJAX response contains a X-
dispatch(callback, request, transport: the
instance JSON HTTP header with some
transport, json) XMLHttpRequest object that
JSON content, then it will be
carried (or is carrying) the
evaluated and passed in the json
AJAX call, json: the X-JSON
argument. If the event is
header of the response (if
onException, the transport
present)
argument will have the exception
instead and json will not be
passed.

The Ajax.Base class


This class is used as the base class for most of the other classes defined in the Ajax object.

Method Kind Arguments Description


options: AJAX
setOptions(options) instance Sets the desired options for the AJAX operation
options
Returns true if the AJAX operation succeeded, false
responseIsSuccess() instance (none)
otherwise
responseIsFailure() instance (none) The opposite of responseIsSuccess().

The Ajax.Request class


Inherits from Ajax.Base

Encapsulates AJAX operations

Property Type Kind Description


List of possible events/statuses reported during an AJAX operation.
Events Array static
The list contains: 'Uninitialized', 'Loading', 'Loaded', 'Interactive', and
Property Type Kind Description
'Complete.'
transport XMLHttpRequest instance The XMLHttpRequest object that carries the AJAX operation
url String instance The URL targeted by the request.
Method Kind Arguments Description
Creates one instance of this object that will
call the given url using the given options.
The onCreate event will be raised during the
constructor call. Important: It is worth
url: the url to
noting that the chosen url is subject to the
be fetched,
[ctor](url, options) constructor browser's security settings. In many cases
options:
the browser will not fetch the url if it is not
AJAX options
from the same host (domain) as the current
page. You should ideally use only local urls
to avoid having to configure or restrict the
user's browser. (Thanks Clay).
This method is typically not called
externally. It is called internally to evaluate
evalJSON() instance (none)
the content of an eventual X-JSON HTTP
header present in the AJAX response.
This method is typically not called
externally. If the AJAX response has a
evalResponse() instance (none) Content-type header of text/javascript then
the response body will be evaluated and this
method will be used.
Retrieves the contents of any HTTP header
name: HTTP
header(name) instance of the AJAX response. Call this only after
header name
the AJAX call is completed.
This method is typically not called
onStateChange() instance (none) externally. It is called by the object itself
when the AJAX call status changes.
This method is typically not called
url: url for the
request(url) instance externally. It is already called during the
AJAX call
constructor call.
readyState: This method is typically not called
respondToReadyState(readyState) instance state number externally. It is called by the object itself
(1 to 4) when the AJAX call status changes.
This method is typically not called
externally. It is called by the object itself to
setRequestHeaders() instance (none)
assemble the HTTP header that will be sent
during the HTTP request.

The options argument object


An important part of the AJAX operations is the options argument. There's no options class per se. Any
object can be passed, as long as it has the expected properties. It is common to create anonymous objects
just for the AJAX calls.

Property Type Default Description


Indicates if the AJAX call will be made
asynchronous Boolean true
asynchronously
Property Type Default Description
'application/
x-www- Sets the Content-Type HTTP header of the Ajax
contentType String
form- request.
urlencoded'
The character encoding used in the body of a
request (especially POST requests.) UTF-8
encoding String 'UTF-8' should be enough in most cases, but if you know
what you're doing, you can use a different
encoding.
Apply eval() to the responseText if the request
comes from the same origin as the page. Use false
encoding Boolean true
to never eval or "force" to always eval regardless
of origin.
If the response is of content type application/json,
applies eval() to the responseText and put the
result in responseJSON. Only happens if the
encoding Boolean true
request comes from the same origin as the page.
Use false to never eval or "force" to always eval
JSON regardless of origin.
method String 'post' Method of the HTTP request
The url-formatted list of values passed to the
request (for example
parameters String or Object '' 'employee=john&month=11') or a hash-like
object that represents the parameters (for example
{employee:'john', month:11}.)
Content passed to in the request's body in case of
postBody String undefined
a HTTP POST
List of HTTP headers to be passed with the
request. This list must have an even number of
items, any odd item is the name of a custom
requestHeaders Array undefined
header, and the following even item is the string
value of that header. Example:['my-header1', 'this
is the value', 'my-other-header', 'another value']
Custom function to be called when the respective
event/status is reached during the AJAX call.
There are several alternatives for the
"XXXXXXXX" in this option, among the
alternatives are the statuses in
Function( Ajax.Request.Events, and the HTTP status codes.
onXXXXXXXX XMLHttpRequest, undefined Example var myOpts = {on403: notAllowed,
Object) onComplete: showResponse, onLoaded:
registerLoaded};. The function used will receive
one argument, containing the XMLHttpRequest
object that is carrying the AJAX operation and
another argument containing the evaluated X-
JSON response HTTP header.
Custom function to be called when the AJAX call
completes successfully. The function used will
Function(
receive one argument, containing the
onSuccess XMLHttpRequest, undefined
XMLHttpRequest object that is carrying the
Object)
AJAX operation and another argument containing
the evaluated X-JSON response HTTP header.
Property Type Default Description
Custom function to be called when the AJAX call
completes with error. The function used will
Function(
receive one argument, containing the
onFailure XMLHttpRequest, undefined
XMLHttpRequest object that is carrying the
Object)
AJAX operation and another argument containing
the evaluated X-JSON response HTTP header.
Custom function to be called when an exceptional
condition happens on the client side of the AJAX
call, like an invalid response or invalid
Function(Ajax.Request,
onException undefined arguments. The function used will receive two
exception)
arguments, containing the Ajax.Request object
that wraps the AJAX operation and the exception
object.
A string that will determine how the new content
will be inserted. Applies only to Ajax.Updater
objects and if nothing is specified, the new
content will completely replace the existing
insertion String undefined
content. If a value s given, it will determine where
the content will be inserted in relation to the
container element. It can be 'before', 'top',
'bottom', or 'after'.
Determines if script blocks will be evaluated
undefined,
evalScripts Boolean when the response arrives. Applies only to
false
Ajax.Updater objects.
Determines the progressive slowdown in a
Ajax.PeriodicalUpdater object refresh rate when
the received response is the same as the last one.
For example, if you use 2, after one of the
decay Number undefined, 1 refreshes produces the same result as the previous
one, the object will wait twice as much time for
the next refresh. If it repeats again, the object will
wait four times as much, and so on. Leave it
undefined or use 1 to avoid the slowdown.
Interval (not frequency) between refreshes, in
frequency Number undefined, 2 seconds. Applies only to Ajax.PeriodicalUpdater
objects.

The Ajax.Updater class


Inherits from Ajax.Request

Used when the requested url returns HTML that you want to inject directly in a specific element of your
page. You can also use this object when the url returns <script type="text/javascript"> blocks that will be
evaluated upon arrival. Use the evalScripts option to work with scripts.

Property Type Kind Description


This object contains two properties: containers.success will be used when the
containers Object instance
AJAX call succeeds, and containers.failure will be used otherwise.
Method Kind Arguments Description
[ctor](container, constructor container:this can be the id of an Creates one instance of this object
Method Kind Arguments Description
url, options) element, the element object itself, or that will call the given url using the
an object with two properties - given options.
object.success element (or id) that
will be used when the AJAX call
succeeds, and object.failure element
(or id) that will be used otherwise. url:
the url to be fetched, options: AJAX
options
This method is typically not called
externally. It is called by the object
itself when the response is received. It
will update the appropriate element
updateContent() instance (none) with the HTML or call the function
passed in the insertion option. The
function will be called with two
arguments, the element to be updated
and the response text.

The Ajax.PeriodicalUpdater class


Inherits from Ajax.Base

This class repeatedly instantiates and uses an Ajax.Updater object to refresh an element on the page, or to
perform any of the other tasks the Ajax.Updater can perform. Check the Ajax.Updater reference for more
information.

Property Type Kind Description


container Object instance This value will be passed straight to the Ajax.Updater's constructor.
url String instance This value will be passed straight to the Ajax.Updater's constructor.
Interval (not frequency) between refreshes, in seconds. Defaults to 2
frequency Number instance seconds. This number will be multiplied by the current decay when
invoking theAjax.Updater object
decay Number instance Keeps the current decay level applied when re-executing the task
updater Ajax.Updater instance The most recently used Ajax.Updater object
The handle to the timer being used to notify the object when it is time for
timer Object instance
the next refresh.
Method Kind Arguments Description
container:this can be the id of an element,
the element object itself, or an object with
two properties - object.success element (or Creates one instance of this
[ctor](container,
constructor id) that will be used when the AJAX call object that will call the given
url, options)
succeeds, and object.failure element (or id) url using the given options.
that will be used otherwise. url: the url to be
fetched, options: AJAX options
This method is typically not
called externally. It is called
start() instance (none) by the object itself to start
performing its periodical
tasks.
stop() instance (none) Causes the object to stop
Method Kind Arguments Description
performing its periodical
tasks. After stopping, the
object will call the callback
given in the onComplete
option (if any.)
This method is typically not
called externally. It is called
by the currently used
updateComplete() instance (none) Ajax.Updater after it
completes the request. It is
used to schedule the next
refresh.
This method is typically not
called externally. It is called
onTimerEvent() instance (none)
internally when it is time for
the next update.

The Element object


This object provides some utility functions for manipulating elements in the DOM.

The Element.Methods object


This object provides some utility functions for manipulating elements in the DOM. You typically do not
call these methods directly from the Element.Methods object, but rather from the Element object, which
gets copies of all of them.

All the methods defined here are automatically added to any element accessed using the $() function. When
they are added to the elements, the first argument (always element) is removed because it's always the
current element itself. So, in short, writing Element.show('myDiv'); is the same as writing
$('myDiv').show();

Method Kind Arguments Description


Changes the position CSS style to
element: element
absolutize(element) instance absolute but takes care of not altering its
object or id.
current size and location on the page.
element: element
addClassName(element, object or id, Adds the given class name to the
instance
className) className: name of a element's class names.
CSS class
element: element
adjacent(element, [expression1 [, object or id, Returns all the element's siblings that
instance
expression2 [...]]]) expressionX: CSS match one of the given CSS rules.
selection rules
Returns an Array with all the ancestors
(parent nodes) of the element. The array
element: element
ancestors(element) instance will start at the first direct parent
object or id
element and go all the way to the html
element.
childOf(element, ancestor) instance element: element Same as descendantOf.
Method Kind Arguments Description
object or id, ancestor:
ancestor candidate
element or id
Returns an Element.ClassNames object
element: element
classNames(element) instance representing the CSS class names
object or id
associated with the given element.
element: element Removes any white space text node
cleanWhitespace(element) instance
object or id children of the element
Copies the size and position of the
element: element source element into the current element.
object or id, source: The options argument can be used to
clonePosition(element, source [, element to be cloned adjust this process. The available
instance
options]) options: object with options are: setLeft, , setTop, setWidth,
settings for fine-tuning setHeight, which are booleans
the clone operation. (true/false,) and offsetTop, offsetLeft,
which are number of pixels.
Returns an Array Error. This text should
not be shown. Please email
courseware@webucator.com to report it:
Array with the total offsets of the
element, including any of the element's
cumulativeOffset(element) instance element: object ancestors offsets. The resulting array is
similar to [total_left_offset,
total_top_offset] Error. This text should
not be shown. Please email
courseware@webucator.com to report it:
[total_left_offset, total_top_offset]
Returns an Array Error. This text should
not be shown. Please email
courseware@webucator.com to report it:
Array with the total offsets of the
element, including any of the element's
ancestors offsets. se this when the
cumulativeScrollOffset(element) instance element: object element is inside parent elements that
scroll. The resulting array is similar to
[total_left_offset, total_top_offset]
Error. This text should not be shown.
Please email
courseware@webucator.com to report it:
[total_left_offset, total_top_offset]
element: element
Returns a Boolean value indicating if
object or id, ancestor:
descendantOf(element, ancestor) instance the element is a descendant (child,
ancestor candidate
grandchild, etc) of the given ancestor.
element or id
Returns an Array with all the
element: element
descendants(element) instance descendants (child nodes — children,
object or id
grandchildren, etc) of the element.
element: element Checks which of the element's
object or id, descendants match the given rule and
down(element, expression,
instance expression: a CSS returns the first one or the Nth one given
index)
selection rule, index: by the zero-based index argument.
index of the returned Lower index values mean closer to the
Method Kind Arguments Description
descendant element.
Returns a Boolean value indicating if
element: element
empty(element) instance the element tag is empty (or has only
object or id
whitespaces)
Returns the dimensions of the element.
element: element
getDimensions(element) instance The returned value is an object with two
object or id
properties: height and width.
element: element
getHeight(element) instance Returns the offsetHeight of the element
object or id
element: element
object or id,
cssProperty name of a Returns the value of the CSS property in
getStyle(element, cssProperty) instance
CSS property (either the given element or null if not present.
format 'prop-name' or
'propName' works).
element: element
getWidth(element) instance Returns the offsetWidth of the element
object or id
element: element
hasClassName(element, object or id, Returns true if the element has the given
instance
className) className: name of a class name as one of its class names.
CSS class
element: element Hides the element by setting its
hide(element) instance
object or id style.display to 'none'.
element: element Returns the element's id. If one does not
identify(element) instance
object or id exist, a new, unique one will be created.
Returns a simplified string
representation of the element's tag. It's
element: element
inspect(element) instance useful for debugging and only contains
object or id
the element's id and css class name, like
<p id="result" class="hilite numeric">
Inserts new content before, after, at the
element: element top or at the bottom if the element. For
object or id insertion: example $(el).insert({top: '<li>new
insert(element, insertion) instance
object describing what item</li>'}). It defaults to insertion at
to insert the bottom if the second argument is the
content itself.
element: element
makeClipping(element) instance
object or id
element: element Changes the element's style.position to
makePositioned(element) instance
object or id 'relative'
Verifies if the element is matched by the
element: element given CSS selector rule. For example, a
object or id, selector: paragraph element with an id of
match(element, selector) instance
string or Selector 'message' would be matched by the
object of a CSS rule selector 'p#message'. This method
returns true or false.
element: element Checks which of the element's posterior
object or id, sibilings match the given rule and
next(element, expression, index) instance expression: a CSS returns the first one or the Nth one given
selection rule, index: by the zero-based index argument.
index of the returned Lower index values mean closer to the
Method Kind Arguments Description
sibilng element.
Returns an Array with all the siblings
element: element that come after the element. The list is
nextSiblings(element) instance
object or id built by recursively finding all the other
elements via the nextSibling property.
element: object or id,
name: event name
(like 'click', 'load',
etc), observer:
Function(evt) to
observe(element, name,
instance handle the event, Shortcut for Event.observe.
observer, useCapture)
useCapture: if true,
handles the event in
the capture phase and
if false in the bubbling
phase.
element: element Checks which of the element's previous
object or id, sibilings match the given rule and
previous(element, expression, expression: a CSS returns the first one or the Nth one given
instance
index) selection rule, index: by the zero-based index argument.
index of the returned Lower index values mean closer to the
sibilng element.
Returns an Array with all the siblings
that come before the element. The list is
element: element
previousSiblings(element) instance built by recursively finding all the other
object or id
elements via the previousSibling
property.
element: element Removes the element from the
remove(element) instance
object or id document.
element: element
removeClassName(element, object or id, Removes the given class name from the
instance
className) className: name of a element's class names.
CSS class
Replaces the entire html of the element
with the given html argument. If the
element: element
given html contains <script
replace(element, html) instance object or id, html:
type="text/javascript"> blocks they will
html content
not be included but they will be
evaluated.
element: element Scrolls the window to the element
scrollTo(element) instance
object or id position.
element: element
object or id, Sets the value of the CSS properties in
setStyle(element,
instance cssPropertyHash Hash the given element, according to the
cssPropertyHash)
object with the styles values in the cssPropertyHash argument.
to be applied.
element: element
select(element, expression1 [, object or id. Finds all the child elements that match
instance
expression2 [...]]) expressionN: CSS one of the given CSS rules.
selectors
show(element) instance element: element Shows the element by resetting its
Method Kind Arguments Description
object or id style.display to ''.
element: element Returns an Array with all the siblings
siblings(element) instance
object or id that come before and after the element.
element: object or id,
name: event name
(like 'click', 'load',
etc), observer:
Function(evt) to
stopObserving(element, name,
instance handle the event, Shortcut for Event.stopObserving.
observer, useCapture)
useCapture: if true,
handles the event in
the capture phase and
if false in the bubbling
phase.
element: element
toggle(element) instance Toggles the visibility of the element.
object or id
element: element
toggleClassName(element, Toggles the presence of the given CSS
instance object or id,
className) class name in the element.
className: CSS class
element: element
undoClipping(element) instance
object or id
element: element
undoPositioned(element) instance Clears the element's style.position to ''
object or id
element: element
Checks which of the element's ancestors
object or id,
match the given rule and returns the first
expression: a CSS
up(element, expression, index) instance one or the Nth one given by the zero-
selection rule, index:
based index argument. Lower index
index of the returned
values mean closer to the element.
ancestor
Replaces the inner html of the element
with the given html argument. If the
element: element
given html contains <script
update(element, html) instance object or id, html:
type="text/javascript"> blocks they will
html content
not be included but they will be
evaluated.
element: element Returns a Boolean value indicating if
visible(element) instance
object or id the element is visible.

You can add your own methods to the Element.Methods object and they will also be copied to the elements
automatically. You only need to ensure that your methods also take the element as the first argument and (if
possible) returns the element object. Here's an example of how to do that. I'll add three new utility methods
to the elements.

//first a helper method


var $CE = function (tagName, attributes, styles) { //short for create element
var el = document.createElement(tagName);
if (attributes)
$H(attributes).each( function (pair) {
eval("el." + pair.key + "='" + pair.value + "'");
});
if (styles)
$H(styles).each( function (pair) {
el.style[pair.key] = pair.value;
});
return $(el);
};

//adding he new methods


Element.addMethods({
//removes any child noes from the element
//example: <div id="myDiv"><b>hello</b></div>
// $('myDiv').clearChildren();
// ==> <div id="myDiv"></div>
clearChildren: function (element) {
element = $(element);
$A(element.childNodes).each( function (e) {
e.parentNode.removeChild(e);
});
return element;
},
//method that creates a new element and appends to the current element
// example: <div id="myDiv">Please</div>
// $('myDiv').append('A',{href:'otherpage.html',
className:'red'}).update('Continue...');
// ==> <div id="myDiv">Please<a href="otherpage.html" class="red">Continue...</a></div>
append: function (element, tagName, attributes, styles) {
element = $(element);
var newEl = $CE(tagName, attributes, styles);
element.appendChild(newEl);
return newEl;//<-- this one returns the new element
},
//appends a text node to the element
// example: <div id="myDiv"><b>hello</b></div>
// $('myDiv').appendText(', John');
// ==> <div id="myDiv"><b>hello</b>, John</div>
appendText: function (element, text){
element = $(element);
var t = document.createTextNode(text);
element.appendChild(t);
return element;
}
});

The Element.ClassNames class


Inherits from Enumerable

Represents the collection of CSS class names associated with an element.

Method Kind Arguments Description


element: any DOM Creates an Element.ClassNames object representing
[ctor](element) constructor
element object or id the CSS class names of the given element.
className: a CSS Includes the given CSS class name in the list of
add(className) instance
class name class names associated with the element.
className: a CSS Removes the given CSS class name from the list of
remove(className) instance
class name class names associated with the element.
Associates the element with the given CSS class
className: a CSS
set(className) instance name, removing any other class names from the
class name
element.

The Abstract object


This object serves as the root for other classes in the library. It does not have any properties or methods.
The classes defined in this object are also treated as traditional abstract classes.
The Field object
This object provides some utility functions for working with input fields in forms. It's simply a shorthand to
Form.Element.

The Form object


This object provides some utility functions for working with data entry forms and their input fields.

Method Kind Arguments Description


Returns a url-formatted list of field names and
form: form element
serialize(form) instance their values, like
object or id
'field1=v1&field2=v2&field3=v3'
form: form element Returns the first enabled field element in the
findFirstElement(form) instance
object or id form.
form: form element Returns an Array containing all the input fields
getElements(form) instance
object or id in the form.
form: form element
object or id, typeName: Returns an Array containing all the <input>
getInputs(form [, the type of the input elements in the form. Optionally, the list can
instance
typeName [, name]]) element, name: the be filtered by the type or name attributes of the
name of the input elements.
element.
form: form element
disable(form) instance Disables all the input fields in the form.
object or id
form: form element
enable(form) instance Enables all the input fields in the form.
object or id
form: form element Activates the first visible, enabled input field
focusFirstElement(form) instance
object or id in the form.
form: form element Resets the form. The same as calling the
reset(form) instance
object or id reset() method of the form object.

The Form.Element object


This object provides some utility functions for working with form elements. These functions have native
DOM equivalents, but those don't return the element as the result of the function call, preventing the
chaining of method calls.

The methods below are not the only methods in this object at runtime. All the methods from
Form.Element.Methods will also be added to this object.

Method Kind Arguments Description


element: element object or id of a form
focus(element) instance Moves the input focus to the field.
field
element: element object or id of a form Selects the value entered in the
select(element) instance
field element.

The Form.Element.Methods object


This object provides some utility functions for working with form field elements, that will be copied over
to any field element accessed via the functions $() and $$().

Similarly to the Element.Methods methods, when they are copied, the first argument is dropped and
becomes the element itself. These methods are also copied to the Form.Element object so you don't
typically use the methods from Form.Element.Methods directly, but rather via the Form.Element object for
consistency.

Method Kind Arguments Description


element: element Moves the input focus to the field and selects its
activate(element) instance
object or id contents.
element: element
clear(element) instance Empties the field.
object or id
element: element Disables the field or button, so it cannot be changed or
disable(element) instance
object or id clicked.
element: element
enable(element) instance Enables the field of button for being changed or clicked.
object or id
element: element
getValue(element) instance Returns the value of the element.
object or id
element: element
present(element) instance Returns true if the field is not empty.
object or id
element: element Returns the element's name=value pair, like
serialize(element) instance
object or id 'elementName=elementValue'

The Form.Element.Serializers object


This object provides some utility functions that are used internally in the library to assist extracting the
current value of the form elements.

Method Kind Arguments Description


element: object or id of a form
Returns an Array with the element's
element that has the checked
inputSelector(element) instance name and value, like ['elementName',
property, like a radio button or
'elementValue']
checkbox.
element: object or id of a form
Returns an Array with the element's
element that has the value
textarea(element) instance name and value, like ['elementName',
property, like a textbox, button
'elementValue']
or password field.
Returns an Array with the element's
element: object of a <select> name and all selected options' values or
select(element) instance
element texts, like ['elementName', 'selOpt1
selOpt4 selOpt9']

The Abstract.TimedObserver class


This class is used as the base class for the other classes that will monitor one element until its value (or
whatever property the derived class defines) changes. This class is used like an abstract class.

Subclasses can be created to monitor things like the input value of an element, or one of the style
properties, or number of rows in a table, or whatever else you may be interested in tracking changes to.
Method Kind Arguments Description
element: element object or id,
[ctor](element, frequency: interval in seconds, Creates an object that will monitor
constructor
frequency, callback) callback: function to be called the element.
when the element changes
Derived classes have to implement
instance, this method to determine what is
getValue() (none)
abstract the current value being monitored
in the element.
This method is typically not called
externally. It is called by the object
registerCallback() instance (none)
itself to start monitoring the
element.
This method is typically not called
externally. It is called by the object
onTimerEvent() instance (none)
itself periodically to check the
element.
Property Type Description
element Object The element object that is being monitored.
frequency Number This is actually the interval in seconds between checks.
Function(Object, The function to be called whenever the element changes. It will receive
callback
String) the element object and the new value.
lastValue String The last value verified in the element.

The Form.Element.Observer class


Inherits from Abstract.TimedObserver

Implementation of an Abstract.TimedObserver that monitors the value of form input elements. Use this
class when you want to monitor an element that does not expose an event that reports the value changes. In
that case you can use the Form.Element.EventObserver class instead.

Method Kind Arguments Description


element: element object or id,
[ctor](element, Inherited from Abstract.TimedObserver.
frequency: interval in seconds,
frequency, constructor Creates an object that will monitor the
callback: function to be called
callback) element's value property.
when the element changes
getValue() instance (none) Returns the element's value.

The Form.Observer class


Inherits from Abstract.TimedObserver

Implementation of an Abstract.TimedObserver that monitors any changes to any data entry element's value
in a form. Use this class when you want to monitor a form that contains a elements that do not expose an
event that reports the value changes. In that case you can use the Form.EventObserver class instead.

Method Kind Arguments Description


[ctor](form, constructor form: form object or id, frequency: Inherited from Abstract.TimedObserver.
Method Kind Arguments Description
frequency, interval in seconds, callback function Creates an object that will monitor the
callback) to be called when any data entry form for changes.
element in the form changes
Returns the serialization of all form's
getValue() instance (none)
data.

The Abstract.EventObserver class


This class is used as the base class for the other classes that execute a callback function whenever a value-
changing event happens for an element.

Multiple objects of type Abstract.EventObserver can be bound to the same element, without one wiping out
the other. The callbacks will be executed in the order they are assigned to the element.

The triggering event is onclick for radio buttons and checkboxes, and onchange for textboxes in general
and listboxes/dropdowns.

Method Kind Arguments Description


element: element object or
[ctor](element, id, callback: function to be Creates an object that will monitor the
constructor
callback) called when the event element.
happens
Derived classes have to implement this
instance,
getValue() (none) method to determine what is the current
abstract
value being monitored in the element.
This method is typically not called
registerCallback() instance (none) externally. It is called by the object to
bind itself to the element's event.
This method is typically not called
externally. It is called by the object to
registerFormCallbacks() instance (none)
bind itself to the events of each data
entry element in the form.
This method is typically not called
onElementEvent() instance (none) externally. It will be bound to the
element's event.
Property Type Description
element Object The element object that is being monitored.
Function(Object, The function to be called whenever the element changes. It will receive
callback
String) the element object and the new value.
lastValue String The last value verified in the element.

The Form.Element.EventObserver class


Inherits from Abstract.EventObserver

Implementation of an Abstract.EventObserver that executes a callback function to the appropriate event of


the form data entry element to detect value changes in the element. If the element does not expose any
event that reports changes, then you can use the Form.Element.Observer class instead.
Method Kind Arguments Description
element: element object or id, Inherited from Abstract.EventObserver.
[ctor](element,
constructor callback: function to be called Creates an object that will monitor the
callback)
when the event happens element's value property.
getValue() instance (none) Returns the element's value

The Form.EventObserver class


Inherits from Abstract.EventObserver

Implementation of an Abstract.EventObserver that monitors any changes to any data entry element
contained in a form, using the elements' events to detect when the value changes. If the form contains
elements that do not expose any event that reports changes, then you can use the Form.Observer class
instead.

Method Kind Arguments Description


form: form object or id, callback: Inherited from Abstract.EventObserver.
[ctor](form,
constructor function to be called when any data Creates an object that will monitor the
callback)
entry element in the form changes form for changes.
getValue() instance (none) Returns the serialization of all form's data.

The Prototype Library Conclusion


Prototype is an incredibly powerful library that not only provides you handy little helpers but, more
importantly, assists you to build your own libraries.

It's solid class creation pattern and AJAX support can confidently be used as the backbone for all your
client-side work.

When combined with the great number of Prototype-based 3rd party libraries, Prototype can make your
JavaScript coding very productive.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript
Tutorial's Table of Contents.
script.aculo.us
In this lesson of the JavaScript tutorial, you will learn...

1. What is, who wrote, who uses, who maintains


2. Where to get and how to make part of your site
3. The visual effects
4. The in-place editors
5. How to create drag and drop elements
6. The auto-completing input fields
7. Where to get more information

script.aculo.us is the most popular add-on to Prototype that exists. It was developed and is maintained by
Thomas Fuchs.

script.aculo.us is also bundled in Ruby on Rails and is extensively used on that platform. The number of
developers already familiar with this library and it's user community make it a great choice for our projects.

On its official site (http://script.aculo.us/) you will find the most current documentation and lists of
additional resources like user-contributed extensions (new visual effects, transitions, etc.) and mailing lists.

The most current source code for script.aculo.us can be found at


http://github.com/madrobby/scriptaculous/tree/master.

Including script.aculo.us in the page


As any other JavaScript library, we include script.aculo.us in our page by means of a script tag referencing
an external file. script.aculo.us is composed of multiple .js files so we better explain the proper way to load
it.

As we will see later, script.aculo.us is divided in several modules, each one implementing a specific
functionality. We can load all the modules by adding only two library references as shown below.

Syntax
<script type="text/javascript" src="scripts/prototype.js"></script>
<script type="text/javascript" src="scripts/scriptaculous.js"></script>

We need a reference to Prototype because script.aculo.us was build completely dependent of Prototype
(actually script.aculo.us, early on, was part of Prototype before spinning off.)

By adding a reference to scriptaculous.js all the modules will be dynamically loaded. The modules are
builder.js, effects.js, dragdrop.js, controls.js, slider.js, and sound.js.

Loading all the modules is clearly an exaggeration and a disrespect with our users unless we are actually
using each one of the modules, what is pretty unlikely. For that reason we can specify the modules we need
explicitly when we reference scriptaculous.js.

Syntax
<script type="text/javascript" src="scripts/prototype.js"></script>
<script type="text/javascript" src="scripts/scriptaculous.js?effects,controls"></script>
The above format will make scriptaculous.js only load effects.js and controls.js.

Although quite handy, we would like to suggest that you avoid this dynamic loading of modules altogether
and be explicit about which modules you need. Just remember to load them in the same order that we listed
a few paragraphs above. The previous example would is rewritten below, which we believe will be clearer
for another developer reading your code.

Syntax
<script type="text/javascript" src="scripts/prototype.js"></script>
<script type="text/javascript" src="scripts/effects.js"></script>
<script type="text/javascript" src="scripts/controls.js"></script>

Effects
One of the main reasons developers use script.aculo.us is because of the visual effects that it implements.
The visual effects can be very useful to call the user's attention to some important event that happened on
the page. Effects can also be used to make visual changes in the page gradually, instead of an abrupt
element insertion or relocation.

The effects are part of the effects.js file and they need Prototype on the page as well.

There are at least two ways to trigger the effects on a given element.

Syntax
//using the constructor (don't forget the 'new'!)
new Effect.EffectName('elementID' [, options]);
//or via the extension added to the DOM elements
$('elementId').visualEffect('effectName' [, options]);

Just like in many parts of Prototype, the options argument is a hash-like object that can provide non-
mandatory adjustments for the effects.

Effects are divided in two main groups, Core Effects and Combined Effects.

Core Effects
Think of the core effects as the simplest and more fundamental effects. Later we will be used to combine
these effects to create richer effects. They are our building blocks.

script.aculo.us Core Effects


Effect Description Options
This effect changes the opacity/transparency of
the element, making it more or less translucid from: initial opacity (0.0 to 1.0), to:
Effect.Opacity
progressively. By default is changes the opacity final opacity.
from 0.0 to 1.0.
x: X-coordinate movement in pixels, y:
Moves the element to another point in the page.
Y-coordinate movement in pixels,
Effect.Move The movement can be specified in relative or
mode: coordinates mode, can be
absolute X and Y coordinates.
'absolute' or 'relative'
Moves the element to another point in the page. scaleX: resize on the X-axis, scaleY:
Effect.Scale The movement can be specified in relative or resize on the Y-axis, scaleContent:
absolute X and Y coordinates. Sample usage: resizes the contents of the element as
script.aculo.us Core Effects
Effect Description Options
new Effect.Scale('elem', 150, {scaleFromCenter: well, scaleFromCenter: resizes the
true}); element from its center instead of from
the top-left corner, scaleFrom: the
starting point of the effect (a percentage
value.)
startcolor: background color to start the
Remember when we implemented the Yellow
effect, defaults to #ffff99, endcolor:
Fade Technique (YFT) a few lessons ago? Well,
color that effect ends at, defaults to
Effect.Highlight scratch that and let's use this effect instead. It
white, restorecolor: color that is used
does the same thing but better and more
after the effect finishes, defaults to the
extensibly.
element's background color.
You can get a lot done with this effect alone.
Simply put, it will change the element from its
current appearance to what is defined by some
form of CSS specification. Sample usage: new
Effect.Morph
Effect.Morph('elem', 'processedOrder', {duration:
1.5}); or new Effect.Morph('elem', {style:
{backgroundColor: '#7f7', height: '120px'} },
{duration: 1.5});

Exercise: Simple Effect Usage


Duration: to 30 minutes.

Let's see how easy it is to apply script.aculo.us effects. In this exercise we will use script.aculo.us to change
the opacity of an element to 50%.

1. Create a method WEBUCATOR.setOpacity(element)


2. Call that method from the button's click passing box2 as the element.
3. The created method should use one of script.aculo.us effects to reduce the opacity of the given
element to 50%.

Code Sample: Scriptaculous/Exercises/simple-effect.html


---- Code Omitted ----
<body>
<h1>A Simple Effect</h1>

<div id="box1">BOX 1</div>


<div id="box2">BOX 2</div>
<input type="button" value="Reduce Opacity"
onclick="alert('not done yet!!!');" />
</body>
---- Code Omitted ----

Where is the solution?

Combined Effects
There's another core effect that we have not shown. It's more of an infrastructure effect. It's the
Effect.Parallel. This effect is used to execute two or more effects simultaneously.
new Effect.Parallel(
[
new Effect.Opacity('notice', { sync: true }),
new Effect.Scale('notice', 100, { sync: true, scaleFrom: 50 })
],
{ duration: 2 });

Note the sync option being passed to both inner effects. This is the clue for script.aculo.us to wait until all
effects are created and execute them all at once.

script.aculo.us comes with a series of effects that are built by pre-configuring or combining the core effects
with Effect.Parallel.

All the combined effects have shortcuts added to the DOM elements but can also be called like the core
effects.

Syntax
//we don't need the 'new' for combined effects
//but if you use it, it doesn't cause any problem
Effect.EffectName('element' [, options]);
//or
$('element').visualEffect('effectName' [, options]);
//or
$('element').effectName( [options] );
script.aculo.us Combined Effects
Effect Description Options
offset: vertical offset after
Effect.ScrollTo Scrolls the page until the element is reached. the element. Will be added
to the scrolling distance.
Shakes the element from left to right a few times to call
Effect.Shake
attention.
Decreases and increases the opacity few times to call
Effect.Pulsate
attention.
Effect.DropOut The element falls down and fades.
Effect.Appear The element's opacity goes from 0.0 to 1.0.
The element's opacity goes from 1.0 to 0.0, then the element
Effect.Fade
is hidden.
The element's height is decreased until it disappears. The
Effect.BlindUp
element is hidden on completion.
The element's height is increased from zero until the
Effect.BlindDown
element's original height.
The element's height is decreased until it disappears. The
contents need to be inside an extra div inside the element
Effect.SlideUp
and it will move up instead of shrinking. The element is
hidden on completion.
The element's height is increased from zero to the element's
original height. The contents need to be inside an extra div
Effect.SlideDown
inside the element and it will move down instead of
expanding.
The element grows and fades. The element is hidden on
Effect.Puff
completion.
The element shrinks towards the upper-left corner. The
Effect.Squish
element is hidden on completion.
Effect.SwitchOff The element flickers quickly then shrinks like and old CRT
script.aculo.us Combined Effects
Effect Description Options
TV set picture. The element is hidden on completion.
The narrows vertically then horizontally until it disappears.
Effect.Fold
The element is hidden on completion.

Effects pout-pourri
The following demo showcases the available effects and the code used to create them.

Code Sample: Scriptaculous/Demos/effects.html


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<title>effects</title>
<style type="text/css" media="screen">
th {text-align:left; font-size:18px; background-color:#777; color:#fff;}
.demo { display:none;}
.demo-content {background-color:#FFB855; padding:10px;}
.demo-content pre {background-color: #aaa;}
#demoArea {height:400px; width:550px; background-color:#eee; }
#demoList { margin:0; list-style-type: none; padding:0;}
#demoList a { text-decoration:none;}
</style>
<script type="text/javascript"
src="../../Libraries/prototype.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/effects.js"></script>
<script type="text/javascript" charset="utf-8">
var WEBUCATOR = {
currentDemo: '',

loadDemo: function (demoName) {


this.restorePreviousDemo();
//move demo content to demo area
var demo = $(demoName);
var content = demo.select('.demo-content')[0];
content.remove();
$('demoArea').insert(content);
//make the code snippet in the demo
// become the actual code
this.importCodeSnippet(demoName, content);
//if a demoName_pre() function exists, call it
(this[demoName + '_pre'] || Prototype.emptyFunction).apply(this);
//remember this demo name to restore it later
this.currentDemo = demoName;
},

importCodeSnippet: function (demoName, content) {


if (typeof this[demoName] === 'undefined') {
var code = content.select('.demoCode')[0];
var functionCode = code.innerHTML.unescapeHTML();
this[demoName] = new Function(functionCode);
}
},

restorePreviousDemo: function () {
if (this.currentDemo !== '') {
var prevDemo = $(this.currentDemo);
var prevContent = $('demoArea').select('.demo-content')[0];
prevContent.remove();
prevDemo.insert(prevContent);
}
},

doMainDemoAction: function () {
this[this.currentDemo]();
},

//cleanup code ....

demoHighlight_pre: function () {
$('theTime').update('');
},

demoOpacity_pre: function () {
$('topBox').setOpacity(1);
},

demoScale_pre: function () {
$('smallBox').setStyle({
fontSize: '11px',
width: '80px', height: '40px',
left: '100px', top: '40px'});
$('smallBox').update('Scriptaculous');
},

demoMove_pre: function () {
$('mover').setStyle({left: '25px', top: '25px'});
},

demoDropOut_pre: function () {
$('droppingBox').show();
},

demoAppear_pre: function () {
$('appearingBox').hide();
},

demoFade_pre: function () {
$('fadingBox').show();
},

demoBlindUp_pre: function () {
$('rollUpBox').show();
},

demoBlindDown_pre: function () {
$('rollDownBox').hide();
},

demoSlideUp_pre: function () {
$('slideUpBox').show();
},

demoSlideDown_pre: function () {
$('slideDownBox').hide();
},

demoPuff_pre: function () {
$('puffingBox').show();
},

demoSwitchOff_pre: function () {
$('tvBox').show();
},

demoSquish_pre: function () {
$('squishable').show();
},

demoFold_pre: function () {
$('napkin').show();
},

demoMorph_pre: function () {
$('willMorph').setStyle(
{ left: '100px', width:'100px', color: '', backgroundColor: '#77E66C'});
},

temp: null
}

</script>
</head>

<body>
<h1>Scriptaculous Effects Sampling</h1>
<table border="0" cellspacing="5" cellpadding="5">

<thead><tr><th>Effect</th><th>Demo</th></tr></thead>
<tbody>
<tr valign="top">
<td>
<ul id="demoList">
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoOpacity');">Effect.Opacity</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoMove');">Effect.Move</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoHighlight');">Effect.Highlight</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoScale');">Effect.Scale</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoMorph');">Effect.Morph</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoScroll');">Effect.ScrollTo</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoDropOut');">Effect.DropOut</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoShake');">Effect.Shake</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoPulsate');">Effect.Pulsate</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoAppear');">Effect.Appear</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoFade');">Effect.Fade</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoBlindUp');">Effect.BlindUp</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoBlindDown');">Effect.BlindDown</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoSlideUp');">Effect.SlideUp</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoSlideDown');">Effect.SlideDown</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoPuff');">Effect.Puff</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoSwitchOff');">Effect.SwitchOff</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoSquish');">Effect.Squish</a>
</li>
<li>
<a href="javascript:void(0);"
onclick="WEBUCATOR.loadDemo('demoFold');">Effect.Fold</a>
</li>

</ul>
</td>
<td>
<div id="demoArea"></div>
</td>
</tr>
</tbody>
</table>

<div id="demoOpacity" class="demo">


<div class="demo-content">
<h3>Effect.Opacity</h3>
<input type="button" value="Change opacity?" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px;">&nbsp;
<div style="background-color:#7D85DA; position:absolute; left:5px; top:5px;
width:100px; height:100px">&nbsp;</div>
<div id="topBox" style="background-color:#77E66C; position:absolute; left:25px;
top:25px; width:100px; height:100px">&nbsp;</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">new Effect.Opacity('topBox', {to: 0.50, duration:
2});</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('topBox').visualEffect('opacity', {to: 0.50, duration: 2});</code></pre>
</div>
</div>

<div id="demoMove" class="demo">


<div class="demo-content">
<h3>Effect.Move</h3>
<input type="button" value="Move it" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="mover" style="background-color:#77E66C; position:absolute; left:25px;
top:25px; width:100px; height:100px">Scriptaculous</div>

</div>
<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">new Effect.Move('mover', {x: 300, y: 75});</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('mover').visualEffect('move', {x: 300, y: 75});</code></pre>
</div>
</div>

<div id="demoScroll" class="demo">


<div class="demo-content">
<h3>Effect.ScrollTo</h3>
<input type="button" value="Go to the element"
onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="height:1200px; border:solid 1px #000;">&nbsp;
</div>
<div id="bottomBox" style="background-color:#77E66C; width:180px; height:40px; text-
align:center; ">
Scriptaculous (the element)
</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">new Effect.ScrollTo('bottomBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('bottomBox').visualEffect('scrollTo');</code></pre>
</div>
</div>

<div id="demoScale" class="demo">


<div class="demo-content">
<h3>Effect.Scale</h3>
<input type="button" value="Resize it" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="smallBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">new Effect.Scale('smallBox', 200,
{scaleFromCenter: true});</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('smallBox').visualEffect('scale', 200,
{scaleFromCenter: true});</code></pre>
</div>
</div>

<div id="demoMorph" class="demo">


<div class="demo-content">
<h3>Effect.Morph</h3>
<input type="button" value="Morph it" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="willMorph" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:100px; height:40px; text-align:center;">Scriptaculous</div>
</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">new Effect.Morph('willMorph',
{ style:
{ backgroundColor:'#ff0000',
color: '#ffffff',
width: '220px',
left: '250px'
}
});</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('willMorph').visualEffect('morph',
{ style:
{ backgroundColor:'#ff0000',
color: '#ffffff',
width: '220px',
left: '250px'
}
});
//or
$('willMorph').morph(
{ backgroundColor:'#ff0000',
fontColor: '#ffffff',
width: '220px'
});</code></pre>
</div>
</div>

<div id="demoHighlight" class="demo">


<div class="demo-content">
<h3>Effect.Highlight</h3>
<input type="button" value="What time is it?"
onclick="WEBUCATOR.doMainDemoAction();"/>
<strong>The time is: </strong> <span id="theTime" ></span>
<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">var time = new Date();
$('theTime').update(time.toString());
new Effect.Highlight('theTime',
{ duration: 2, endcolor:'#FFB855' }
);</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('theTime').visualEffect('highlight', {to: 0.50, duration: 2});
//or
$('theTime').highlight({to: 0.50, duration: 2});</code></pre>

</div>
</div>

<div id="demoDropOut" class="demo">


<div class="demo-content">
<h3>Effect.DropOut</h3>
<input type="button" value="Wave goodbye to it"
onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="droppingBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.DropOut('droppingBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('droppingBox').visualEffect('dropOut');
//or
$('droppngBox').dropOut();</code></pre>
</div>
</div>

<div id="demoShake" class="demo">


<div class="demo-content">
<h3>Effect.Shake</h3>
<input type="button" value="Hey, look at me" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="willShake" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.Shake('willShake');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('willShake').visualEffect('shake');
//or
$('willSahke').shake();</code></pre>
</div>
</div>

<div id="demoPulsate" class="demo">


<div class="demo-content">
<h3>Effect.Pulsate</h3>
<input type="button" value="Hey, I'm here" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="willPulsate" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.Pulsate('willPulsate');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('willPulsate').visualEffect('pulsate');
//or
$('willPulsate').pulsate();</code></pre>
</div>
</div>

<div id="demoAppear" class="demo">


<div class="demo-content">
<h3>Effect.Appear</h3>
<input type="button" value="Show it" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="appearingBox" style="background-color:#77E66C; position:absolute;
left:100px; top:40px; width:80px; height:40px; text-align:center; font-size:11px;
display:none">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.Appear('appearingBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('appearingBox').visualEffect('appear');
//or
$('appearingBox').appear();</code></pre>
</div>
</div>

<div id="demoFade" class="demo">


<div class="demo-content">
<h3>Effect.Fade</h3>
<input type="button" value="Vanish" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="fadingBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>
<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.Fade('fadingBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('fadingBox').visualEffect('fade');
//or
$('fadingBox').fade();</code></pre>
</div>
</div>

<div id="demoBlindUp" class="demo">


<div class="demo-content">
<h3>Effect.BlindUp</h3>
<input type="button" value="Roll it up" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="rollUpBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.BlindUp('rollUpBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('rollUpBox').visualEffect('blindUp');
//or
$('rollUpBox').blindUp();</code></pre>
</div>
</div>

<div id="demoBlindDown" class="demo">


<div class="demo-content">
<h3>Effect.BlindDown</h3>
<input type="button" value="Roll it down" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="rollDownBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-size:11px;
display:none;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.BlindDown('rollDownBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('rollDownBox').visualEffect('blindDown');
//or
$('rollDownBox').blindDown();</code></pre>
</div>
</div>

<div id="demoSlideUp" class="demo">


<div class="demo-content">
<h3>Effect.SlideUp</h3>
<input type="button" value="Push it up" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="slideUpBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;"><div>Scriptaculous</div></div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.SlideUp('slideUpBox');</code></pre>
<strong>Alternatives:</strong>
<pre><code>$('slideUpBox').visualEffect('slideUp');
//or
$('slideUpBox').slideUp();</code></pre>
</div>
</div>

<div id="demoSlideDown" class="demo">


<div class="demo-content">
<h3>Effect.SlideDown</h3>
<input type="button" value="Push it down" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="slideDownBox" style="background-color:#77E66C; position:absolute;
left:100px; top:40px; width:80px; height:40px; text-align:center; font-size:11px;
display:none;"><div>Scriptaculous</div></div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.SlideDown('slideDownBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('slideDownBox').visualEffect('slideDown');
//or
$('slideDownBox').slideDown();</code></pre>
</div>
</div>

<div id="demoPuff" class="demo">


<div class="demo-content">
<h3>Effect.Puff</h3>
<input type="button" value="Make it go up in smoke"
onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="puffingBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:120px; height:40px; text-align:center;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.Puff('puffingBox', {duration: .5});</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('puffingBox').visualEffect('puff', {duration: .5});
//or
$('puffingBox').puff({duration: .5});</code></pre>
</div>
</div>

<div id="demoSwitchOff" class="demo">


<div class="demo-content">
<h3>Effect.SwitchOff</h3>
<input type="button" value="Turn it Off" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="tvBox" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:120px; height:40px; text-align:center; font-size:11px;">Scriptaculous
TV</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.SwitchOff('tvBox');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('tvBox').visualEffect('switchOff');
//or
$('tvBox').switchOff();</code></pre>
</div>
</div>

<div id="demoSquish" class="demo">


<div class="demo-content">
<h3>Effect.Squish</h3>
<input type="button" value="Squish it" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="squishable" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">Effect.Squish('squishable');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('squishable').visualEffect('squish');
//or
$('squishable').squish();</code></pre>
</div>
</div>

<div id="demoFold" class="demo">


<div class="demo-content">
<h3>Effect.Fold</h3>
<input type="button" value="Fold it" onclick="WEBUCATOR.doMainDemoAction();"/>
<div style="position:relative; height:200px; border:solid 1px #000;">&nbsp;
<div id="napkin" style="background-color:#77E66C; position:absolute; left:100px;
top:40px; width:80px; height:40px; text-align:center; font-
size:11px;">Scriptaculous</div>

</div>

<br/><br/>
<strong>Code:</strong>
<pre><code class="demoCode">new Effect.Fold('napkin');</code></pre>

<strong>Alternatives:</strong>
<pre><code>$('napkin').visualEffect('fold');
//or
$('napkin').fold();</code></pre>
</div>
</div>

</body>
</html>

Common effect options


All effects share a few options that can be used to gain more control of the effect execution.

Option Description
delay Number o seconds before the effect starts. Defaults to 0.0.
Used to trigger effects in succession. It defaults to 'parallel' but can also be 'front', 'end', and
queue
'with-last'
duration Length of the effect in seconds. Defaults to 1.0.
Number of frames per second. Defaults to 100 but 25 is good enough for the human eye and
fps
avoids unnecessary CPU usage.
sync Use true when running effects in parallel.
from Starting point of the effect. A number between 0.0 and 1.0.
Option Description
to Ending point of the effect. A number between 0.0 and 1.0.
beforeStart Callback function that is invoked just before the effect starts.
beforeSetup Callback function that is invoked just before the first frame is calculated.
Callback function that is invoked right after the first frame is calculated and before it is
afterSetup
rendered.
beforeUpdate Callback function that is invoked before each frame is rendered.
afterUpdate Callback function that is invoked after each frame is rendered.
beforeFinish Callback function that is invoked before the effect runs its finalization logic.
afterFinish Callback function that is invoked after the effect runs its finalization logic.
Specifies the pace of the effect progression. It defaults to Effect.Transitions.sinoidal but is ca
also be Effect.Transitions.spring, Effect.Transitions.linear, Effect.Transitions.flicker,
Effect.Transitions.wobble, Effect.Transitions.pulse, Effect.Transitions.none,
transition
Effect.Transitions.full, and Effect.Transitions.reverse. It can also be customized by passing a
function that receives a number between 0.0 and 1.0 and returns another number in the same
range.

Dragging, Sorting, and Dropping


Drag and drop is a common user interface metaphor in desktop applications. It's not as prevalent in web
applications, though. Nevertheless, this is something that can greatly help users in some situations.

The dragging and dropping cycle involves a number of decisions. Among them: what to drag, what to grab
it by, where to drop it, what to do after it is dropped. script.aculo.us helps with each of these problems.

It's very easy to make an element draggable. See the example below.

Code Sample: Scriptaculous/Demos/drag-simple.html


---- Code Omitted ----

<script type="text/javascript"
src="../../Libraries/prototype.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/effects.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/dragdrop.js"></script>

<script type="text/javascript" charset="utf-8">


document.observe('dom:loaded', function () {
//it's easy to make an element draggable:
new Draggable('theImage');
} );
</script>
---- Code Omitted ----

<h1>This image is draggable</h1>


<img id="theImage" src="../Common/olympics.png" alt="olympics" />
---- Code Omitted ----

All we needed to make the img element draggable was to instantiate a new Draggable object associated
with that element.
Syntax
new Draggable('theImage');

That was easy indeed, but that's not where the story ends. Just like with the Effect objects, we also have a
number of options that we can pass in the second argument of the constructor.

Syntax
new Draggable(element, { /* options here */ });
Option Description
Specifies if the drag will be limited. Defaults to false but can also be 'vertical' or
constraint
'horizontal'.
Amount of time (in seconds) to initiate the dragging after the mouse button is pressed.
delay This can be useful to avoid dragging when the user just wanted to click a button or link.
Defaults to zero.
Effect that will be applied to the element when the dragging ends. The default is to change
endeffect the opacity to 100% in .2 seconds. This is a function that takes the dragged element as the
argument.
Determines if a clone element will be created during the drag, leaving the original element
ghosting
in its original place until a drop occurs. Default is false.
Use this when we want to define one child element in the draggable element to serve as
handle the handle for dragging the bigger element. It defaults to false but can also be a DOM
element, an id, or a CSS class name.
Function that will be called during dragging when the mouse is moved and the element is
onDrag about to be have its position changed. The function will receive the Draggable object as
the first parameter.
Function that will be called when the dragging ends. The function will receive the
onEnd
Draggable object as the first parameter.
Function that will be called when the dragging starts. The function will receive the
onStart
Draggable object as the first parameter.
When working with Droppables this will indicate if the element should go back to the
revert
original position if it's not dropped in a Droppable. Defaults to false.
This creates the effect that will be used when reverting the drag. Defaults to an
revertEffect Effect.Move but can be replaced with a function that takes the element, the dragged X, and
the dragged Y in pixels.
The scroll container for the drag. When defined, the container will scroll when the dragged
scroll element nears its edges. It can be the window object or any other element that has
scrolling enabled.
scrollSensitivity Number of pixels from the edges of the container that trigger the scrolling.
A number representing the pixels per second that the container will scroll when the
scrollSpeed element is dragged near the edges. Defaults to 15. This is actually the minimum speed
because the speed will be greater when the closer to the border the drag is.
Defines a grid that will cause the dragging to snap to a grid. It can be a number, which will
snap be the number of pixels between each snapping position in the grid. It can also be a 2-
element array, containing the number of pixel in the X and Y direction respectively.
Effect that will be applied to the element when the dragging starts. The default is to
starteffect change the opacity to 50% in .2 seconds. This is a function that takes the dragged element
as the argument.
Number that will be used as the element's z-index while being dragged to ensure it is
zindex
above the other elements. Default is 1000.

The next example illustrates how the use of dragging and effects to create a simple puzzle game.
Code Sample: Scriptaculous/Demos/shuffle.html
---- Code Omitted ----

var WEBUCATOR = {
image: { width: 600.0, height:380.0 },
tiles: [],

createGrid: function () {
var columns = 4, rows = 3;
var cellWidth = this.image.width/columns;
var cellHeight = this.image.height/rows;
var left, top, cell, tile;

for (var row = 0; row < rows; row++) {


for (var col = 0; col < columns; col++) {
left = col * cellWidth;
top = row * cellHeight;
tile = this.createTile(left, top, cellWidth, cellHeight);
tile.originalPosition = {x: left, y: top};

$('grid').insert(tile);
this.tiles.push(tile);
}
}

this.makeTilesDraggable();
},

createTile: function (left, top, width, height) {


var tile = new Element('div', {'class':'cell'});
tile.setStyle({
width: width + 'px',
height: height + 'px',
left: left + 'px',
top: top + 'px',
backgroundPosition: '-' + left + 'px -' + top + 'px'
});

return tile;
},

makeTilesDraggable: function () {
this.tiles.each( function (tile) {
new Draggable(tile);
});
},

shuffleGrid: function () {
this.tiles.each( function (tile) {
var left = Math.floor(Math.random() * WEBUCATOR.image.width);
var top = Math.floor(Math.random() * WEBUCATOR.image.height);

tile.visualEffect('move', {x: left, y: top, mode:'absolute'});


});
},

restoreGrid: function () {
this.tiles.each( function (tile) {
tile.visualEffect('move',
Object.extend( tile.originalPosition, {mode:'absolute'} )
);
});
}
};

document.observe('dom:loaded', function () { WEBUCATOR.createGrid();} );


---- Code Omitted ----
Exercise: Dragging with options
Duration: 15 to 30 minutes.

We will create a Draggable that is a little bit more than the default.

1. Find the place where you are suppose to add your code (see comments.)
2. Create a Draggable that will enable dragging of both the image and the title bar together.
3. Check that it works.
4. Change the code to allow dragging only by the title bar.
5. Check that it still works.
6. Add code to make the dragging carry only a copy of the picture.
7. Check that it still works.
8. Add code to force the dragging to happen in chunks of 30 pixels horizontally and 50 vertically.

Code Sample: Scriptaculous/Exercises/drag-handle.html


---- Code Omitted ----
<script type="text/javascript"
src="../../Libraries/prototype.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/effects.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/dragdrop.js"></script>

<script type="text/javascript" charset="utf-8">


document.observe('dom:loaded', function () {

//Write code here to make the


// picture below draggable by the red title bar
// also make the drag adhere to a 30 by 50 grid (X by Y)
// change the dragging behavior to leave the original picture
// behind and use a copy until it gets finally dropped
});

</script>
---- Code Omitted ----
<h1>This image is draggable by the title bar</h1>
<div id="picture" class="draggablePicture">
<div class="titlebar">Olympics</div>
<div><img id="theImage" src="../Common/olympics.png" alt="olympics" /></div>
</div>
---- Code Omitted ----

Where is the solution?

The Draggable object has a number of members as listed below.

Member Description
destroy() A method that will remove the dragging capabilities of the element.
dragging A Boolean value indicating if the element is currently being dragged.
The DOM element that is associated with this object. In other words, that's the element that can
element
be dragged.
If specified as an option, this will contain a reference to the DOM element that will be used as the
handle
handle for dragging the main element.
The options set for this Drggable. This includes both the options specified at the constructor call
options
and all the default options that were not overridden.
Droppables
Many times dragging items around is not all that useful unless you have a designated place to drop the
items. The Drop part of Drag and Drop is handled by the Droppable object.

We create dropping zones in our page by making adding an element to the Droppables list.

Syntax
Droppables.add(element [, options]);

The available options for the Draggables are listed below.

Option Description
Name of a CSS class that will restrict which elements can be dropped in this drop zone. Only
accept
draggables with that class will be successfully dropped.
Instead of a CSS class we can pass an element in this option so only draggables that are
containment
children of this element will be accepted.
Name of a CSS class that will be added to the drop zone element while an element in dragged
hoverclass
over it.
Takes a function that will be called when an element is dropped. The function will receive
onDrop three arguments: the element being dropped, the drop zone element, and the event
information.

Exercise: Dragging then dropping


Duration: 30 to 45 minutes.

We will create two dropping zones in a page, where we can drop book cover images dragged from another
part of the page.

1. Find the place where you are suppose to add your code (see comments.)
2. Write code to make all the existing book covers draggable
3. Check that it works.
4. Make the green and yellow areas drop zones for the books
5. When a book is dropped we want to create a duplicate image of the book in the drop zone.
6. Make the drop zones show a border when the books are dragged over them.

Code Sample: Scriptaculous/Exercises/simple-drop.html


---- Code Omitted ----
<script type="text/javascript" charset="utf-8">
document.observe('dom:loaded', function () {
/* here we need to make the books draggable
and make the DIVs with ids alreadyRead and willRead drop zones

we will create a copy of the book images in the drop zone


when a book is dropped there
*/

});

var WEBUCATOR = {
/* here we will create a function to
handle the drop event for both drop zones
*/
};

</script>
---- Code Omitted ----
<body>
<h1>Books that I must read</h1>
<table>
<tr>
<th>Available<br/>books</th>
<th>Books<br/>I've read</th>
<th>Books I<br/>should read</th>
</tr>
<tr>
<td>
<div id="available">
<img id="book1" src="../Common/poeaa.jpg" alt="Poeaa" class="book"/>
<img id="book2" src="../Common/ddd.jpg" alt="ddd" class="book"/>
<img id="book3" src="../Common/wewlc.jpg" alt="wewlc" class="book"/>
<img id="book4" src="../Common/tpp.jpg" alt="pragprog" class="book"/>
</div>
</td>
<td><div id="alreadyRead"></div></td>
<td><div id="willRead"></div></td>
</tr>
</table>
</body>
---- Code Omitted ----

Where is the solution?

Sortables
It's very common to use dragging to reorder items in a list. That's a much better user interface design than
using "move up" or "move down" buttons. For that reason script.aculo.us offers that behavior pre-packaged
in the Sortable object.

To make items sortable we just need to make the parent element sortable, like we can see below.

Code Sample: Scriptaculous/Demos/sort-books.html


---- Code Omitted ----
<script type="text/javascript" charset="utf-8">
document.observe('dom:loaded', function () {
Sortable.create('books');
});

</script>
---- Code Omitted ----
<ul id="books">
<li>
<div class="book">
<img src="../Common/poeaa.jpg" alt="Poeaa" align="left"/>
<h2>Patterns of Enterprise Application Architecture</h2>
<h3>Martin Fowler</h3>
</div>
</li>
<li>
<div class="book">
<img src="../Common/ddd.jpg" alt="ddd" align="left"/>
<h2>Domain-Driven Design</h2>
<h3>Eric Evans</h3>
</div>
</li>
<li>
<div class="book">
<img src="../Common/wewlc.jpg" alt="wewlc" align="left"/>
<h2>Working Effectively With Legacy Code</h2>
<h3>Michael Feathers</h3>
</div>
</li>
<li>
<div class="book">
<img src="../Common/tpp.jpg" alt="pragprog" align="left"/>
<h2>The Pragmatic Programmer</h2>
<h3>Andy Hunt and Dave Thomas</h3>
</div>
</li>
</ul>
---- Code Omitted ----

When creating a Sortable object we can also pass some options in the second argument of Sortable.create().
One such option is the onUpdate, which takes a function that will receive the parent element as the
argument.

To be able to use the onUpdate callback we need to add an id attribute to each li element in our list. The ids
need to be in the format xxxxxx_value, where the value part will be extracted and considered the value of
the item.

The Sortable gives us the current sequence via the Sortable.serialize(listElementID) method. This returns a
string formated like listElementID[]=value1&listElementID[]=value3&listElementID[]=value2. Although
this format looks a little funky, it's due to script.aculo.us strong bond with Ruby on Rails and it's not too
hard to live with in non-Ruby on Rails platforms. Our next exercise will show how to use that in PHP.

Exercise: AJAX Sorting


Duration: 30 to 45 minutes.

In this exercise we will use a Sortable to reorder a list of items and submit each order update to the server
using AJAX.

1. Add the necessary references to external .js files to use Sortable.


2. Find the place where you are suppose to add your code (see comments.)
3. Make the list of books sortable upon page load.
4. Check that it works.
5. Add code to the WEBUCATOR object that will be called whenever the order changes.
6. Verify that the code gets called after updates (hint: the li elements will need id attributes.)
7. Change the code to perform an Ajax.Update to the URL ../Common/save-sequence.php passing
the serialized sortable as a form field named seq. The updater will direct its result to the div
element with id result.

Code Sample: Scriptaculous/Exercises/sort-save.html


---- Code Omitted ----
<script type="text/javascript" charset="utf-8">
var WEBUCATOR = {
//we will add code here to handle events and start ajax calls

};

document.observe('dom:loaded', function () {
//We will add code here to create the sortable
});

</script>
---- Code Omitted ----
<div id="result" >&nbsp;</div>
<ul id="books">
<li>
<div class="book">
<img src="../Common/poeaa.jpg" alt="Poeaa" align="left"/>
<h2>Patterns of Enterprise Application Architecture</h2>
<h3>Martin Fowler</h3>
</div>
</li>
<li>
<div class="book">
<img src="../Common/ddd.jpg" alt="ddd" align="left"/>
<h2>Domain-Driven Design</h2>
<h3>Eric Evans</h3>
</div>
</li>
<li>
<div class="book">
<img src="../Common/wewlc.jpg" alt="wewlc" align="left"/>
<h2>Working Effectively With Legacy Code</h2>
<h3>Michael Feathers</h3>
</div>
</li>
<li>
<div class="book">
<img src="../Common/tpp.jpg" alt="pragprog" align="left"/>
<h2>The Pragmatic Programmer</h2>
<h3>Andy Hunt and Dave Thomas</h3>
</div>
</li>
</ul>
---- Code Omitted ----

Code Sample: Scriptaculous/Common/save-sequence.php


<?php
parse_str($_POST['seq']);

$received = "";
for($i = 0; $i < count($books); $i++)
{
//here we would for example
// save the posted sequence to the database
//In our sample we will just echo back the posted values
$index = $i + 1;
$received = $received . " [$index: $books[$i]]";
}
echo $received
?>
Where is the solution?

Controls
script.aculo.us contains a few classes to assist creating user interface elements commonly known as
widgets. The approach script.aculo.us takes is to attach objects of those classes to existing HTML elements
and enhance them with added behaviors.

In order to use the controls in script.aculo.us we need to include the controls.js file, which will need
effects.js and prototype.js
Syntax
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="effects.js"></script>
<script type="text/javascript" src="controls.js"></script>

Autocompleter
The auto-completion functionality was popularized by Google Suggest, where a regular input text field
shows a list of possible search terms before you're done typing the entire term. This is now a more or less
common feature in many sites.

What happens behind the scenes is that the web page is issuing AJAX requests to the server, passing
whatever you have typed so far, getting a list of possible words or phrases that you might be planning to
enter, and displaying the list. Then you can just select one from the list instead of finishing typing it off.

script.aculo.us comes with two flavors of autocompletion controls. One is fed by an AJAX call just like
described above. The other one (referred to as local) gets its list from an array already in the page. The two
controls support a lot of the same functionality, differing obviously in the source of the suggested items and
the options that are related to the AJAX request itself.

Here's how we create an Autocompleter. First an example of a local one.

Syntax
var states = ['Alabama', 'Alaska', ... ,'Wisconsin', 'Wyoming'];
Autocompleter.Local(fieldElement, popUpElement, states);

Now an AJAX-based one.

Syntax
new Ajax.Autocompleter(fieldElement, popUpElement, '/url/to/getSuggestions' [, options]);

In both cases fieldElement is the element or id of an input text field where the typing will occur and
popUpElement is the element or id of a div that will be used as the pop-up list that will be displayed under
the text field.

Below is a working example of a local Autocompleter that looks up an array with the list of the U.S. states.

Code Sample: Scriptaculous/Demos/suggest-local.html


---- Code Omitted ----
<script type="text/javascript"
src="../../Libraries/prototype.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/effects.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/controls.js"></script>

<script type="text/javascript" charset="utf-8">


var WEBUCATOR = {
usStates: [
'Alabama' ,
'Alaska' ,
'Arizona' ,
---- Code Omitted ----
'Wisconsin' ,
'Wyoming'
]
};

document.observe('dom:loaded', function () {
new Autocompleter.Local('userState', 'suggestPopUp', WEBUCATOR.usStates);
} );

</script>
---- Code Omitted ----
What State do you live in?
<input type="text" id="userState" />
<div id="suggestPopUp" class="suggestions"/>
---- Code Omitted ----

As you can see there isn't a lot of code to look at. Surprisingly enough the majority of the work that we
have to do is related to CSS rules to make the pop-up look nice. In this example we removed the bullet
points from each li element in the pop-up and highlighted the currently selected item by adding a different
background color to the item with the class name selected (script.aculo.us takes care of putting that class
name in the correct item for us.)

The same example can be converted to an AJAX version provided we write the server side code. This
particular example isn't actually a good candidate for being AJAX-fied because it draws results from a
relatively short and fixed list, but let's do it anyway for illustrative purposes.

Code Sample: Scriptaculous/Demos/suggest-ajax.html


---- Code Omitted ----
<script type="text/javascript"
src="../../Libraries/prototype.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/effects.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/controls.js"></script>

<script type="text/javascript" charset="utf-8">


document.observe('dom:loaded', function () {
new Ajax.Autocompleter('userState',
'suggestPopUp', '../Common/lookup-state.php');
});
</script>
---- Code Omitted ----
What State do you live in?
<input type="text" id="userState" name="state" />
---- Code Omitted ----

Code Sample: Scriptaculous/Common/lookup-state.php


<?php
$states = array(
"Alabama","Alaska" ,"Arizona","Arkansas" ,"California" ,
"Colorado" ,"Connecticut","Delaware" ,"Florida","Georgia",
"Hawaii" ,"Idaho","Illinois" ,"Indiana","Iowa" ,
"Kansas" , "Kentucky" ,"Louisiana","Maine","Maryland" ,
"Massachusetts","Michigan" ,"Minnesota","Mississippi",
"Missouri" ,"Montana","Nebraska" ,"Nevada" ,
"New Hampshire","New Jersey" ,"New Mexico" ,"New York" ,
"North Carolina" ,"North Dakota" ,"Ohio" ,"Oklahoma" ,
"Oregon" ,"Pennsylvania" ,"Rhode Island" ,"South Carolina" ,
"South Dakota" ,"Tennessee","Texas","Utah" ,"Vermont","Virginia" ,
"Washington" ,"Washington D.C.","West Virginia"
);

$term = $_POST["state"];
echo "<ul>";
$returns = 0;

foreach($states as $st) {
$pos1 = stripos($st, $term);

if ($pos1 !== false) {


//we will build: <li>bla bla bla <strong>TERM HERE</strong> bla bla</li>
$text = substr($st, 0, $pos1);
$text = $text . "<strong>" . substr($st, $pos1, strlen($term)) . "</strong>";
$text = $text . substr($st, $pos1 + strlen($term));
echo "<li>$text</li>";
$returns+=1;
}

if($returns == 10){
break;
}
}

echo "</ul>";
?>

The lookup-state.php receives the value entered by the user in a POSTed form field with the same name as
the input field's name attribute (not the id, watch out for this possible tripwire.)

With the value in hands, the server script is responsible for figuring out what the returned suggestions
should be and return them in ul/il elements. In the above example we highlight the typed text in the result
list.

The Autocompleter takes a number of options. Three are shared by both the local and AJAX versions.

Option Description
If this is set to true and there's only one value being suggested, then that value is automatically
autoSelect
selected. This option defaults to false.
This is a misnomer. This option specifies the number of seconds between refreshing the
frequency
suggestions. Defaults to 0.4.
Number of characters that need to be typed before the first suggestions list is produced. Defaults
minChars
to 1.

The Autocompleter.Local adds its own specific options.

Option Description
Defaults to false and determines if the suggestions should include any items that contain the
fullSearch
typed text anywhere, not just beginnings of words.
ignoreCase Determines if character casing is disregarded in the comparisons. Defaults to true.
When set to true the search algorithm will look for suggestions that begin with the typed text.
partialSearch The default value is false where it matches any suggestion that has a word that begins with
the typed text.
Minimum number of typed characters that cause a partial search to be performed. Defaults to
partialChars
2.
Method that performs the actual work. The default value is the algorithm that obeys all the
selector above options. In the rare event that you need something completely different (like searching
in a XML document,) you can pass this option with a function that receives the autocompleter
Option Description
instance, builds and returns the ul/li DOM structure.

As expected, the Ajax.Autocompleter also has a number of options that control how it works.

Option Description
If you need to customize the creation of the submitted value and parameter name, this option
callback lets you pass a function that will receive a reference to the input element and the typed text
and returns the querystring-formatted 'param=value'.
Id or reference to a DOM element that will automatically be displayed and hidden during the
indicator AJAX calls. This is usually a reference to an img element with some animated glyph that lets
the user know some work is being done.
Just like the original Ajax.Request, this lets us change the HTTP method from the default
method
POST to GET.
Fixed set of parameters to always be send to the AJAX URL. These parameters are encoded in
parameters
URL querystring format, like 'par1=abc&par2=xyz'.
The submitted parameter name is the same as the name attribute of the input field. This
paramName
options lets you change that to whatever name you desire.
Class name of an element inside the suggested li that will provide the text for the selection.
select
This is useful when the suggested items are richer than just text-only li items.
String containing a separator character or an array of separators to be used when the text field
tokens is expected to collect more than one suggestions, like a To: field in an email form, where you
can choose more than one recipient for the message.

Exercise: AJAX Autocompleter with options


Duration: 30 to 45 minutes.

Let's use Ajax.Autocompleter objects to create a very interesting user interface for finding books.

1. Add the necessary references to external .js files to use the Ajax.Autocompleter.
2. Find the place where you are suppose to add your code (see comments.)
3. Add code to the method WEBUCATOR.createAutocompleter() to take a number as an argument
and create an Ajax.Autocompleter for the input field named 'bookN'.
4. The autocompleter needs to call the URL ../Common/lookup-book.php.
5. lookup-book.php expects the desired text in a parameter named bookTitle.
6. Add code to the document load event to create the 3 autocompleters.
7. Run the code and verify that the suggestPopUp gets populated with the books list.
8. The book selection is still broken. Let's fix that by collecting only the text inside the element with
a CSS class name of book_title.
9. Check that this last change works.
10. To add a little more of flair, let's make an animated progress icon show to the side of each input
field when the AJAX call is in progress.
11. Use the image file ../Common/ajax-loader.gif.
12. Modify WEBUCATOR.createAutocompleter() to create and insert the img element with this icon
right after each text box, initially hidden.

Code Sample: Scriptaculous/Exercises/important-books.html


---- Code Omitted ----
<script type="text/javascript" charset="utf-8">
var WEBUCATOR = {
createAutocompleter: function (/* ??? */) {
//change this function to create the autocompleter
// with the necessary options
}
};

document.observe('dom:loaded', function () {
//add code here to create each of the 3
// autocompleters using the WEBUCATOR.createAutocompleter() method
});
</script>
---- Code Omitted ----
<body>
<h1>Name 3 important programming books:</h1>
1 - <input type="text" id="book1" name="book1" /> <br />
2 - <input type="text" id="book2" name="book2" /> <br />
3 - <input type="text" id="book3" name="book3" /> <br />

<div id="suggestPopUp" class="suggestions"/>


</body>
---- Code Omitted ----

Code Sample: Scriptaculous/Common/lookup-book.php


<?php
$books = array(
array('poeaa', 'Patterns of Enterprise Application Architecture', 'Martin Fowler'),
array('ddd', 'Domain-Driven Design', 'Eric Evans'),
array('wewlc', 'Working Effectively With Legacy Code', 'Michael Feathers'),
array('tpp', 'The Pragmatic Programmer', 'Andy Hunt and Dave Thomas')
);

$term = $_POST["bookTitle"];

//simulate lengthy task


//sleep(1);

echo "<ul>";

foreach($books as $b) {

$pos1 = stripos($b[1], $term);


$pos2 = stripos($b[2], $term);

if ($pos1 !== false || $pos2 !== false) {

echo "<li><div class=\"book\">";


echo "<img src=\"../Common/$b[0].jpg\" alt=\"$b[1]\" align=\"left\"
style=\"width:50px;height:70px\"/>";
echo "<h2 class=\"book_title\">$b[1]</h2>";
echo "<h3>$b[2]</h3>";
echo "</div></li>";
}

echo "</ul>";
?>
Where is the solution?

InPlaceEditor
The InPlaceEditor adds behavior to static text elements so that they, upon being clicked, become input text
fields and a pair or buttons or links to accept or cancel the edit operation. Accepting the input causes an
AJAX call to happen so the value can be persisted immediately.

There are two flavors of in-place editing in script.aculo.us, Ajax.InPlaceEditor and


Ajax.InPlaceCollectionEditor. The former makes the static text become a text box. The latter uses a drop
down list instead, limiting the possible resulting value to one of the list items.

Creating either type of editor can be very simple but there are also a large number of options, which we will
discuss shortly. First let's see how the minimal usage looks like.

Code Sample: Scriptaculous/Demos/inplace-simple.html


---- Code Omitted ----
<script type="text/javascript"
src="../../Libraries/prototype.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/effects.js"></script>
<script type="text/javascript"
src="../../Libraries/scriptaculous/controls.js"></script>

<script type="text/javascript" charset="utf-8">


document.observe('dom:loaded', function () {
new Ajax.InPlaceEditor('userName', '../Common/echo.php');
new Ajax.InPlaceCollectionEditor('rate', '../Common/echo.php',
{collection: ['Excellent', 'Good', 'Fair', 'Unsatisfactory', 'Horrible']});
} );

</script>
---- Code Omitted ----

<p>
<span class="fieldLabel">Your Name:</span>
<br/>
<span id="userName" class="field">[your name here]</span>
</p>
<p>
<span class="fieldLabel">How would you rate our service:</span>
<br/>
<span id="rate" class="field">Fair</span>
</p>
---- Code Omitted ----

The above code uses the following helper PHP script named echo.php.

Code Sample: Scriptaculous/Common/echo.php


<?php

//this script simply returns a posted value. By default the


// name of the posted item is "value" but it can be changed
// via the "key" query string parameter: echo.php?key=otherField
$key = $_GET["key"];
if ($key === null) {
$key = "value";
}
echo $_POST[$key];
?>

This very basic example gives us the behavior displayed in the images below.
Before clicking After clicking

The default operation of these controls is to accept the value when the Return key is pressed or the ok
button is clicked. The control will abort the update if Esc is pressed or the cancel link is clicked.

When the value is accepted an AJAX call to the given URL is made, posting the entered text in the value
form parameter and the id of the element in the editorId parameter.

The server is expected to return the final value of the operation, i.e. the HTML text that will become the
new static text. It usually is simply the exact same value that was posted, but we will see that there are
options to enable richer operations.

One important thing to note is that the control is capable of multi-line edits. For that to happen the
element's content must have line break characters (\r: carriage returns or \n: line feeds) or that the rows
option is greater than 1. When that happens, the editor will be a textarea field instead of a simple input text
field.

As you can see, there's a lot of functionality in the control even with the default settings, but there's a lot
that can be customized just by specifying a few options.

Option Description
These are the options that are passed to the Ajax.Updater. Defaults to { evalScripts:
ajaxOptions
true }.
If the rows option is 1 and the editor is multi-line, then this value will be used
autoRows
instead. Defaults to 3.
Function that is called to format the values posted in the AJAX call. It will be
callback passed the form element created around the editor and the value entered in the
editor.
Specifies what type of element will be created to cancel the operation. The values
cancelControl
can be 'button', 'link', or false. The last one avoids any cancel button or link.
clickToEditText Text that is shown in a tooltip when the text is not in edit mode.
Array of items used to create the drop down list in the
collection
Ajax.InPlaceCollectionEditor.
cols Number of columns of the created input text field. Defaults to 40.
Reference or id of an element used to put the text in edit mode. The text itself
externalControl
remains capable of entering edit mode upon being clicked.
Specifies if the input field will be activated or just receive focus after being created.
fieldPostCreation
Possible values are 'focus' or 'activate', which is the default (it selects the text.)
CSS class name applied to the form element that is created to house the edit field.
formClassName
Defaults to inplaceeditor-form.
The id of the created form. Defaults to ELEMENT_ID-inplaceeditor, where
formId
ELEMENT_ID is the id of the original text element.
hoverClassName CSS class that is applied to the text element when the mouse is over it.
Specifies that the we expect the server to return the final HTML content of the
element. It defaults to true. We use false when we want to process the server
htmlResponse
response and then determine the element's final content. This option works with the
onComplete option.
loadingText When using the loadTextURL option, this is the text that will be displayed while the
Option Description
text of the edit field is being fetched. Defaults to 'Loading...'.
URL that will be called to provide the text content of the edit field. This can be
loadTextURL useful when the text we want to edit is not HTML and we want the user to type in a
syntax like Textile, Markdown, Wikitext, etc.
Specifies what type of element will be created to accept the operation. The values
okControl
can be 'button', 'link', or false. The last one avoids any ok button or link.
Called when the AJAX request ends. It gets passed the Ajax.Response and the
onComplete
element.
onEnterEditMode Called when the control enters edit mode. It gets passed the control instance.
Called when the mouse hovers over the element. It gets passed the control instance.
onEnterHover
The default value causes the element to be highlighted.
Called when there's an AJAX error. It gets passed the control and the
onFailure
Ajax.Response. By default a simple alert box is displayed.
This is called to give you a chance to tweak the form when it's created. It is passed
onFormCustomization
the control and the form element.
onLeaveEditMode Called when the control leaves edit mode. It gets passed the control instance.
Called when the mouse hovers over the element. It gets passed the control instance.
onLeaveHover
The default value causes an Effect.Highlight to be applied to the element.
If the default parameter name of value doesn't work for you, you can choose a
paramName
different one with this option.
rows Number of rows in the textarea input field that is created for multi-line edits.
savingClassName CSS class name that is applied to the saving text when it is being displayed.
savingText Text that is displayed while the AJAX call is in progress.
size The desired size of the single-line editor field. No default value.
Determines if HTML tags will be removed from the AJAX response text. Defaults
stripLoadedTextTags
to false.
When true causes the control to accept the value when it looses focus. The default is
submitOnBlur
false.

script.aculo.us Conclusion
We can get a lot done with the effects and UI widgets that come with script.aculo.us. Learning when to use
the effects is what will make the difference between a smooth user experience and that annoying website
that insists in getting in your way with unnecessary tricks.

The best part of script.aculo.us is the framework mentality that guided it's design. The library is full of
extensions points that let you customize as little or as much as you need and still leverage reusable
functionality.

To continue to learn JavaScript go to the top of this page and click on the next lesson in this JavaScript
Tutorial's Table of Contents.

You might also like