By now, you have an appreciation of HTML and some background with javaScript. So far, however, they have not been connected with each other in any meaningful way. We have written javascript on a web page, but it does not seem to have any clear relationship with the page. In order to be useful, we ought to be able to connect javaScript with HTML. Ideally, a javascript program would be able to communicate with the page it 'lives' in, would be able to respond to various events that occur in the life of the page (if, for example the user clicks on a button or enters text in a text box), and should be able to dynamically modify the contents of the page (For example, maybe it should say 'good morning', 'good afternoon' or 'good night' based on the time at which the page was requested by the client).
Javascript and other client-side languages achieve this effect through something called the document object model. This is essentially a model for describing a web page that already exists. The document object model is heavily dependant on an idea called object oriented design. That is, the page, all the constituent elements in it, and even the browser are considered objects.
Object oriented programming (OOP) is one of the most important trends in computing in the last decade or so. The basic idea is that we can think of various parts of a program as objects, much like the real world.
The physical world we are used to is full of objects. Consider the office stapler. It is a good example of an object that we can all picture. Staplers have very recognizable characteristics that can be broken into a few main categories.
First, it has properties. Properties are those characteristics that describe the stapler. It might have a color property that describes what color the stapler is. It might also have a stapleSize property that tells what kind of staples the stapler can hold. It might also have a numberOfStaples property that explains how many staples are left. Properties are very similar to the variables we have already investigated. They have names, types, and default (initial values). The major distinction between properties and traditional variables is that properties are attached directly to objects. The numberOfStaples property doesn't make sense unless it is attached to a stapler. So, we might refer to the number of staples this way:
alert(myStapler.numberOfStaples);or we might add staples to it this way:
myStapler.numberOfStaples += 100;Note the syntax here. myStapler is the name of a stapler object, and numberOfStaples is the name of one of its properties. Object oriented languages frequently use this kind of syntax.
In the DOM, the 'core' object is the Document. A web page is essentially a document. Documents have a number of interesting properties. Look at the example below to see how we can manipulate the document.bgcolor property.
<html>
<head>
<title>Background Switcher</title>
</head>
<body bgcolor = "white">
<center>
<h1>Background Switcher<hr></h1>
This page will change colors!!
</center>
<hr>
</body>
<script>
document.bgColor = "red";
alert("press for a new color");
document.bgColor = "orange";
alert("press for a new color");
document.bgColor = "yellow";
alert("press for a new color");
document.bgColor = "green";
alert("press for a new color");
document.bgColor = "blue";
alert("press for a new color");
document.bgColor = "indigo";
alert("press for a new color");
document.bgColor = "violet";
</script>
</html>
When you access this page, you will see that it changes colors whenever we assign a new value to the bgcolor property of the document object. This can be a very useful feature. In effect, it is very much like changing the bgcolor attribute of the <body> tag, except we can do it on the fly through a script. Another interesting effect can be achieved by eliminating the alert commands. This will cause the colors to change in rapid succession. Although this is certainly an attention-grabbing technique, you should not over-use it, as it will probably annoy your users. (Unless maybe you are writing a disco page or something else that merits a lot of flash and distraction).
The document object has some other interesting properties. The following code will illustrate some of them.
<html>
<head>
<title>Document Properties example</title>
</head>
<body bgcolor = "white">
<center>
<h1>Document Properties example<hr></h1>
</center>
<hr>
</body>
<script>
alert("background: " + document.bgColor);
alert("domain: " + document.domain);
alert("last changed: " + document.lastModified);
alert("URL: " + document.location);
alert("Last page: " + document.referrer);
alert("Title: " + document.title);
</script>
</html>
The output of this page would look something like this:
Properties do not all have the same behavior. Some, such as document.bgColor can be read from and written to. Other properties, like property.domain, can be read, but cannot be changed by a script. If you think about this, it makes a lot of sense. We can't really change what page a server comes from inside a script in the page. Not all browsers have exactly the same objects, and they don't all support the same properties. In this text, we will generally stick with examples that will work in every reasonably modern browser (Netscape 4+ and Microsoft Internet Explorer 4+). Consult an up-to-date reference manual to determine which properties will be available, or stick to the 'universal' ones we will be dealing with in this book.
In addition to properties, objects have methods. If properties are like adjectives (they describe characteristics about the object), methods are like verbs. Methods are the things an object can do. Our stapler would have a fasten method. In computing, when programmers design an object, they think about the characteristics of the object, and these become properties. They also think about what the object should be able to do, and write programs that perform these actions. These programs are the object's methods. Often, they feel just like commands, except they use the object oriented syntax. Take a look at some of the methods of the document object in the example below:
<html>
<head>
<title>Document Methods example</title>
</head>
<body bgcolor = "white">
<center>
<h1>Document Methods example<hr></h1>
</center>
<script>
var userName;
username = prompt("What is your name?");
document.write("<h3>Hello, " + userName + "!");
</script>
</body>
</html>
As you can see, this program requests the user's name, then prints it onto the page. There's a couple of interesting things going on here. First, the page's contents are being modified AS IT IS BEING CREATED. Most of the page is being dumped to the browser directly from the server, but the script interrupts the loading of the page to ask the user her name. We then use the write method of the document object. The write method is a form of output. It takes a string parameter (much like the alert does) and outputs it to the web page. The nice thing about the document.write() method is that it integrates the text into the page. As you can see, we can include HTML formatting commands in the text we send to the document.write mothod.
Events are stimuli that an object recognizes. A stapler might have a 'jam' event that occurs when one of the stples gets stuck. Events are basically signals that an object sends out, which tells that something has occurred. Programmers can then write code that is triggered by the event. Look at this example:
<html>
<head>
<title>Event Example</title>
</head>
<body bgcolor = "white">
<center>
<h1>Event Example<hr></h1>
</center>
<form name = theForm>
<input type = button
name = btnHi
value = "don't click me"
onClick = 'alert("Ouch!!")'>
</form>
<hr>
</body>
</html>
There's a couple of important lessons here. First, note that we used a form. Many of the more interesting things you can do with javascript rely on the use of a form and its component objects. As you know, there is very little you can do with form elements without a scripting language, so this is a motivation for learning javascript. We will give the form and all the form objects names using the name attribute. This is important, because we will use the names to refer to the objects in our javascript code.
We put a button inside the form. Notice that we named it, and we added the onClick parameter. This is how the DOM recognizes events. Objects which might generate events have an onClick parameter. You can feed that parameter one line of javascript code, which we have done here. You might be curious about the use of quotes. In javaScript, we can alternate between single and double quotes. That's a good thing, because our line of javascript contains a string, and it IS a string in its own right.
The onclick event is the one you will encounter more than any. It is the main reason that the button exists. Most of your code will happen only as a response to some user event, and that event is usually the clicking of a mouse button. There are a few other events that occaisionally merit being called, but we will bring them up as we need them. Of course you can also look them up. Be careful! The browsers do not all handle the same events in the same way.
That 'one line' of javascript that you are allowed in the event handler was great, but most of the time you want to do things that are a little more involved. Below you will see exactly the same program, but it now works a different way:
<html>
<head>
<title>Event Example with a function</title>
<script>
function sayOuch(){
//this 'mini program says ouch
//it can be as many lines long as I wish
alert("Ouch!!!");
} // end function
</script>
</head>
<body bgcolor = "white">
<center>
<h1>Event Example with a function<hr></h1>
</center>
<form name = theForm>
<input type = button
name = btnHi
value = "don't click me"
onClick = "sayOuch()">
</form>
<hr>
</body>
</html>
Functions are exciting because they allow us to generate new commands by combining the things we already know how to do. A function is nothing more than grouping together several lines of code and giving it a name. Once that is done, we can invoke the function by calling its name. In the same way that a variable is a place-holder for data, a function is a place-holder for instructions. We usually store functions up in the header area, so they will be defined before they are needed in the code. This is much more efficient than the way we have been dealing with code just 'in the middle' of the html. We can call the function any number of times, and the function can do some more sophisticated kinds of things. Now we are truly doing event-driven programming. What this means is we can now have a page respond to user input in some way.
So far, we have one method of input (the prompt command) and two methods of output (alert and document.write()). These techniques have served us so far, but they are limited. The modal dialogs (prompt and alert) stop the flow of the program, and they can be annoying to the user. It would be really nice to be able to have our program more cleanly integrated into the web page.
The document.write() method does give us an excellent output technique, but it has some problems. The user is not guaranteed to see the output of the command until the page has finished loading. This makes it much harder for us to write truly interactive programs that appear to hold 'conversations' with the user.
Examine the code below for an example of how input and output are done using the document object model and event driven programming.
<html>
<head>
<title>I/O and the Document Object Model</title>
<script>
function doName(){
//grabs values of name parts, and concatenates them into a full name
var fullName = "";
//input the values
fullName += window.document.theForm.txtFName.value;
fullName += " ";
fullName += window.document.theForm.txtMI.value;
fullName += " ";
fullName += window.document.theForm.txtLName.value;
//output the value
window.document.theForm.txtFullName.value = fullName;
} // end function
</script>
</head>
<body bgcolor = "white">
<center>
<h1>I/O and the Document Object Model<hr></h1>
</center>
<form name = "theForm">
<table border = 1>
<tr>
<td>last name</td>
<td>
<input type = text
name = txtLName
value = "">
</td>
</tr>
<tr>
<td>first name</td>
<td>
<input type = text
name = txtFName
value = "">
</td>
</tr>
<tr>
<td>middle initial</td>
<td>
<input type = text
name = txtMI
value = "">
</td>
</tr>
<tr>
<td colspan = 2>
<center>
<input type = button
value = "show full name"
onClick = "doName()">
</center>
</td>
</tr>
<tr>
<td colspan = 2>
<center>
<input type = text
name = txtFullName
value = "">
</center>
</td>
</tr>
</table>
</form>
<hr>
</body>
</html>
Of course the text object is not the only one in the DOM hierarchy that might return a value. HTML authors also place radio buttons, selection objects, checkboxes, textareas, and other various objects in their forms, and we need to know how to respond to them.
One class of objects is extremely easy to work with. These are the components that act pretty much like textboxes. In standard HTML, the textarea, password box, and hidden fields are all much like text boxes. We can write the same kind of javascript to manipulate the contents of these input devices. Note that we cannot use javascript to write to the contents of a hidden field. Remember to use the entire hierarchy when dealing with these objects. For example, if you use a textbox called 'txtStuff' on a form called 'theForm', you can refer to its value as window.document.theForm.txtStuff.value.
<html>
<head>
<title>Check box demo</title>
<script>
function processForm(){
//look at all the textboxes and determine which ones are checked
var result = "";
if (window.document.theForm.chkcountry.checked == true){
result += "The user likes country. \n";
} // end if
if (window.document.theForm.chkrock.checked == true){
result += "The user likes rock. \n";
} // end if
if (window.document.theForm.chkjazz.checked == true){
result += "The user likes jazz. \n";
} // end if
if (window.document.theForm.chkrandb.checked == true){
result += "The user likes r and b. \n";
} // end if
if (window.document.theForm.chkclassical.checked == true){
result += "The user likes classical. \n";
} // end if
alert(result);
} // end processForm
</script>
</head>
<body>
<center>
<h1>Check box demo</h1>
</center>
<form name = theForm>
<h3>What's your favorite music?</h3>
Please check all that apply:
<br>
<input type = "checkbox"
name = "chkcountry"
value = "country">Country and Western<br>
<input type = "checkbox"
name = "chkrock"
value = "rock">Rock and Roll<br>
<input type = "checkbox"
name = "chkjazz"
value = "jazz">Jazz<br>
<input type = "checkbox"
name = "chkrandb"
value = "randb">Rythm and Blues <br>
<input type = "checkbox"
name = "chkclassical"
value = "classical">Classical<br>
<input type = "button"
value = "OK"
onClick = processForm()>
</form>
</body>
</html>
As you can see, this is reasonably straightforward. In this case, I did not use the value property of the checkbox elements, although we could have done so. In general, when you work with checkboxes, you will want to do some kind of a conditional check on the checked property of the item.
Radio buttons can be a little tricky to work with, but they can be worth the effort. Recall that radio buttons work in groups. Only one item in a radio group can be checked, just as most radio tuners only allow you to be connected to one station at a time. The machanism we used to get this behavior was giving all the radio objects the same name property.
Several items with the same name is an example of an array. Consider the boxer George Foreman. Apparently, he has named all of his sons George as well. Imagine the chaos in the household. Probably Mrs. Foreman has resorted to some sort of numbering system so she can tell all the Georges apart. The original might be called George[1], and the oldest boy George[2], and so on. If she wanted to find out who was supposed to take out the garbage, she might line them all up and ask each one "George, were you supposed to do the garbage?"
This is exactly the strategy used deal with radio buttons and many other kinds of arrays. We are commonly called to step through the elements of an array, figuring out some value that relates to the elements. As usual, an example might be clearer than an explanation on its own, so examine this code:
<html>
<head>
<title>Radio Button Example</title>
<script>
function processForm(){
//steps through every element of the radio array,
//and returns that value of the one that was selected
var counter = 0;
var result = "";
//use a for loop to step through the array
for(counter = 0; counter < 3; counter++){
//check to see if the current element is selected
if (window.document.theForm.optSize[counter].checked == true){
result = window.document.theForm.optSize[counter].value;
} // end if
} // end for loop
alert(result);
} // end processForm
</script>
</head>
<body>
<center>
<h1>Radio Button Example</h1>
</center>
<h3>What size would you like?</h3>
<form name = theForm>
<input type = "radio"
name = "optSize"
value = "small">small<br>
<input type = "radio"
name = "optSize"
value = "medium">medium<br>
<input type = "radio"
name = "optSize"
value = "large">large<br>
<input type = "button"
value = "ok"
onClick = processForm()>
</form>
</body>
</html>
As you can see, we are basically thinking of the entire list of radio buttons as one element, and we are using the loop to look at the elements individually. Once we have done this, we can extract the value property that was stored in the HTML.
If you want to make the code a little easier to read, you can assign the current radio button to a variable. This does not work in every browser, but it can make your code much easier to work with. Here's the script from the last example re-written to work that way:
function processForm(){
//steps through every element of the radio array,
//and returns that value of the one that was selected
var counter = 0;
var result = "";
var thisOption;
//use a for loop to step through the array
for(counter = 0; counter < 3; counter++){
//assign the current element to the thisOption variable
thisOption = window.document.theForm.optSize[counter];
//check to see if the current element is selected
if (thisOption.checked == true){
result = thisOption.value;
} // end if
} // end for loop
alert(result);
} // end processForm
<html>
<head>
<title>Demonstration of select object</title>
<script>
function processForm(){
//process the select object
var result = "Thank you for choosing the ";
var theSelect;
var choice = 0;
var theOption;
//assign the entire selection object to a variable
theSelect = window.document.theForm.selItems
//figure out which item was chosen
choice = theSelect.selectedIndex;
//grab the appropriate option element
theOption = theSelect.options[choice];
//it's value property to result
result += theOption.value;
alert(result);
} // end processForm
</script>
</head>
<body>
<center>
<h1>Demonstration of select object</h1>
</center>
<form name = theForm>
<h3>Please choose an item from our catalog:</h3>
<select name = selItems>
<option value = "cheese">Venezualan Beaver Cheese</option>
<option value = "badger">Giant Wooden Badger</option>
<option value = "penguin">Exploding penguin</option>
</select>
<input type = "button"
value = "ok"
onClick = processForm()>
</form>
</body>
</html>
In the code above, we extracted the value we wanted through a series of steps. There are more efficient techniques, but this one is probably the clearest, and easiest to debug. First, we created a bunch of variables. We will use a variable to hold the selection object. We need another variable to hold the index of the item the user chose, and another for the item itself. Finally, we will use a variable for the output.
First, we assign theSelect the value of the selection object. Javascript variables are not always the simple things like strings and integers. More complex elements like DOM objects can be assigned to variables as well! This has a lot to do with the power of the DOM and dynamic html. In this case, we will be manipulating the properties of the selection object, so it's easiest to assign it to a variable. You can also think of this as a 'shortcut' to the object, so we don't have to use its long name. Now, when we want to refer to the selection object, we can refer to the variable theSelect rather than having to say window.document.theForm.selItems This is of course much easier to read and write.
theSelect is a complex object, and it contains a lot of information. What we want to know is which element the user selected, and the value property associated with that element. Unfortunately, the process for this in javascript is a little obtuse, but it isn't really difficult. There's just a few steps involved. The selection object has a selectedIndex property which returns the numeric index of whatever item was selected (The first item on the list has an index of zero). That information on its own is not all that helpful, but we will need it soon.
The select object has a number of option elements attached to it. These elements are essentially a list, in the order that the option tags were written to the html page. In programming, we refer to numbered lists of items as arrays, and we use special notation to deal with arrays. In most c-like languages, square brackets [] are used to denote an array.
If we were trying to keep score on a miniature golf course, we might think of a list of scores, one for each hole. We might use the hole number as an index. So, we might write the score for hole one as score[1] If we wanted to write a program that added up the values on a scorecard, we might use a loop, like this:
for (hole = 1; hole <= 9; hole++){
totalScore += score[hole];
} // end for loop
This practice of using a for loop to step through an array is very common.
<html>
<head>
<title>Writing to another frame</title>
<frameset rows = "60%, 40%">
<frame src = "frmCode.html">
<frame src = "blank.html"
name = "frmOutput">
</frameset>
</head>
</html>
Note that we named one of the frames. This is frequently done in
plain HTML for the target attribute of anchor tags. It is
exceptionally useful in this particular case, as you will see.
<html>
<head>
<script>
function printToFrame(text){
parent.window.frmOutput.document.write(text);
parent.window.frmOutput.document.close();
} // end printToFrame();
</script>
</head>
<body bgColor = "White">
<center>
<h1>Writing output to another frame</h1>
(presumes there is a frame called frmOutput available)
<hr>
<form name = "myForm">
Type in some HTML below...
<br>
<textArea name = txtInput
rows = 10
cols = 50>
<!-- sample html... change it if you want -->
<center>
<font color = blue
size = +8>
Whoo Hoo!
<br>
<img src = "http://www.cs.iupui.edu/~aharris/face.gif">
</font>
</center>
</textArea>
<br>
<input type = "button"
value = "show the HTML above in the other frame"
onClick = printToFrame(window.document.myForm.txtInput.value)>
<hr>
</form>
</center>
</body>
</html>
As usual, it's smart to look at the HTML first, before you worry about
the script. Basically, we've got a form with a textarea and a button
on it. The textarea calls a function. Additionally, it sends a value
to the function. You can see that the onclick statement has stuff
inside the parentheses of the function call. The thing in the
parentheses is a parameter. In this case, we want to send the value
of the text box to the function. If you look at the function
definition, you will see that there is a variable name (text) in the
parentheses. Essentially, text is like a brand new variable, that
will automatically contain the value that was sent to it. So,
whenever this program is called, the value of text will immediately be
assigned as the value of the textbox object. This is one way to make
your code cleaner. Functions can have more than one parameter, but
you must ensure that if your function has three parameters, you always
include three values when you call it.
function printToFrame(text){
window.parent.frmOutput.document.write(text);
window.parent.frmOutput.document.close();
} // end printToFrame();
There are only two lines of code here. The first one calls the parent
object (which is the parent of the current window, or the browser
itself). From there, it looks for the frmOutput frame, and the
document in that frame. The write method of that frame's document
object is invoked, meaning the text variable is written to the frame.
<html>
<head>
<title>
Writing to an external window
</title>
<script>
//GLOBAL variable called myWindow.
//I will use it in multiple functions, so I will declare it
//outside ALL functions
var myWindow;
function showPageExtern(){
//opens a new window and shows a page in that window
//uses default window arguments
myWindow = window.open("http://www.cs.iupui.edu/~aharris/220html");
} // end showPageExtern()
function makeWindow(text){
//NOTE: no spaces in the second parameter string!!!
myWindow = window.open("","myWindow","width=300,height=300");
myWindow.document.write(text);
myWindow.document.close();
} // end makeWindow
function closeWindow(){
myWindow.close();
//note this is ENTIRELY different than myWindow.document.close();
}// end closeWindow
</script>
</head>
<body bgColor = "White">
<center>
<form name = "myForm">
<h1>Using External Windows</h1>
<input type = "button"
value = "Show Andy's page in a window"
onClick = showPageExtern()>
<hr>
Type in some HTML below...
<br>
<textArea name = txtInput
rows = 10
cols = 50>
<!-- sample html... change it if you want -->
<center>
<font color = blue
size = +8>
Whoo Hoo!
<br>
<img src = "http://www.cs.iupui.edu/~aharris/face.gif">
</font>
</center>
</textArea>
<br>
<input type = "button"
value = "show the HTML above in a window"
onClick = makeWindow(window.document.myForm.txtInput.value)>
<hr>
<input type = "button"
value = "close the window"
onclick = closeWindow()>
</form>
</center>
</body>
</html>
The HTML for this page was quite similar to the frame output example.
We have added two more buttons, to illustrate some options. The
script also has some new features. For the first time, we have a
script that contains more than one function. This is legal, and often
a good idea. Here we have a function for each button, which is a
common arrangement. Note also that we have a variable created OUTSIDE
all the functions. This is called a GLOBAL variable. The basic idea
is very simple: Each function is its own little entity. Any
variables created inside the function have meaning ONLY inside that
function. If we have a variable that more than one function must
share, there are a couple of ways we can share the value. The easiest
is to create a global variable. (NOTE: there are dangers inherent in
global variables!! You should not use them capriciously!)