In this section, we introduce the JavaScript scripting language as a client-side method for validation and other simple tasks. JavaScript isn't a full-fledged programming language like PHP: it can't connect to databases, it offers only limited interaction with certain system resources, and it can't do most tasks a web database application requires. However, JavaScript is good for interacting with a form and for controlling the display of data to the user.
Client-side validation with JavaScript is optional but has benefits, including faster response to the user than server-side validation, a reduction in web server load, and a reduction in network traffic. Also, unlike server-side validation, it can be implemented as interactive validation where errors are checked as they occur and field-by-field reporting where error messages are shown individually. However, validation in the client tier is unreliable: the user can bypass the validation through design, error, or misconfiguration of their web browser. For that reason, client-side validation should be used only to improve speed, reduce load, and add features, and never to replace server-side validation.
|
Besides validation, there are many other common uses of JavaScript in web database applications including:
Simple interaction with form data. For example, JavaScript is often used to calculate values and display these in an input widget.
Enhancing user interactions by adding dynamic elements to a web page. Common features include pull-down menus, mouseover changes to the presentation (rollovers), and dialog boxes.
Customizing the browser and using information from the browser to enhance presentation.
Most of these techniques are oriented around events. An event is an action that can be trapped through JavaScript code, such as a mouse passing over an object, a window opening, or a user clicking on a button.
The next section introduces JavaScript through a simple example. After that, we show you the basics of JavaScript by contrasting and comparing it with PHP, and then we show you several more examples including a case study. However, this section isn't comprehensive and isn't aimed as a replacement for many of the excellent resources that are available; selected resources are listed in Appendix G.
Consider the short JavaScript validation example in Example 9-5.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Simple JavaScript Example</title> <script type="text/javascript"> <!-- Hide the script from old browsers function containsblanks(s) { for(var i = 0; i < s.value.length; i++) { var c = s.value.charAt(i); if ((c == ' ') || (c == '\n') || (c == '\t')) { alert('The field must not contain whitespace'); return false; } } return true; } // end hiding --> </script> </head> <body> <h1>Username Form</h1> <form onSubmit="return(containsblanks(document.userform.username));" method="POST" name="userform" action="test.php"> <input type="text" name="username" size=10> <input type="submit"> </form> </body> </html>
This example is designed to check if an optional username field contains whitespace and, if so, to show a dialog box containing an error message to the user. The dialog box is shown in Figure 9-1. The example contains a mixture of HTML and JavaScript, and almost all the JavaScript is encapsulated between the <script> and </script> tags in the <head> tag of the document.
The JavaScript function containsBlanks( ) is called when the user submits the form. The function call is part of the form element:
<form onSubmit="return(containsblanks(document.userform.username));" method="post" name="userform" action="test.php">
When the submission event occurs (when the user presses the Submit button or presses the Enter key while the cursor is in the text widget) the onSubmit event is triggered. In this case, the result is that the function containsblanks( ) is called with one parameter, document.userform.username. The object document refers to the document loaded in the browser window, the userform is the name of the form itself, and username is the name of the input widget within the form. The function call itself is wrapped in a return( ) expression. The overall result of executing containsblanks( ) is that if the function returns false, the form isn't submitted to the server; if the function returns true, the HTTP request proceeds as usual.
The function containsblanks( ) works as follows:
A for loop iterates through the characters entered by the user. The expression s.value.length refers to the length of the string value entered by the user into the username widget. The length property is one of the predefined properties of the value attribute of the <input> widget.
Each character in the string entered by the user is assigned to a character variable c using the expression s.value.charAt(i) to return the characters in the value entered by the user. The value attribute of the widget has an associated method charAt( ) that returns the value of the character at the position passed as a parameter. For example, if the user enters test in the widget, s.value.charAt(0) returns t, and s.value.charAt(1) returns e.
The if statement checks whether the current character is a space, a tab character, or a carriage return. If so, the alert( ) method is called with an error string as a parameter. The alert( ) method presents a dialog box in the browser that shows the error message and has an OK button, as shown in Figure 9-1. When the user clicks OK, the function returns false, and the submission process stops.
If the string doesn't contain any whitespace, the function containsblanks( ) returns true, and the form submits as usual.
HTML comment tags are included inside the <script> tags and surround the JavaScript script. This is good practice, because if JavaScript is disabled or the user has an old browser that knows nothing about scripts, the comments hide the script from a potentially confused browser. An old browser happily displays the HTML page as usual. In addition, an old browser or one that has JavaScript turned off will ignore the onSubmit event handler in the form element.
The syntax of JavaScript is similar to PHP and to other languages such as C and Java. Table 9-2 compares some of the basic features of PHP and JavaScript that we used in Example 9-5 and others that are used later in this chapter. The key differences are that JavaScript variables aren't prefixed with a dollar sign, local variables must be declared in JavaScript, different open and close script tags are used, and string concatenation in JavaScript uses a plus sign and PHP uses a period. Other than that, the languages are very similar when used for basic tasks.
Language component |
PHP |
JavaScript |
---|---|---|
Open and close script tags |
<?php ?> |
<script type="text/javascript"> </script> or <% %> |
Block statement |
{ } |
{ } |
Multi-line comment |
/* hello */ |
/* hello */ |
Single-line comment |
// hello |
// hello |
Constant declaration |
define("z", 1); |
const a = 1; |
Variable declaration |
Not required |
Required for local variables, var a = 0; |
Variable assignment |
$a = 0; |
a = 0; |
Assignment shortcut style |
$a += 5; |
a += 5; |
Variable typing |
At runtime |
At runtime |
Statement terminator |
; |
; or the end-of-line |
Equality value testing |
Double-equals, == |
Double-equals, == |
Equality type and value testing |
Triple-equals, === |
Triple equals, === |
Inequality testing |
!= |
!= |
Strings |
"string" 'string' |
"string" 'string' |
String constants |
\n and \t |
\n and \t |
String concatenation |
$a = $b . $c; |
$a = $b + $c; |
Boolean values |
true false |
true false |
Logical AND |
&& |
&& |
Logical OR |
|| |
|| |
Logical NOT |
! |
! |
In PHP, output to the browser is generated using the print or printf statements, or by using a template and template methods as discussed in Chapter 7. In JavaScript, there are several different ways output can be produced including writing output to the browser window as a document is created, creating dialog boxes, updating values in form widgets, and creating new windows.
To write output to a window, the writeln( ) method can be used:
<script type="text/javascript"> document.writeln("Hello, world."); </script>
The document object refers to the document that is displayed in the browser window, and writeln( ) is a method associated with that document. You can write to a document only as it's created, you can't use this method to write text to the document after it's been rendered in the browser. The basic objects and methods are discussed later in this section.
In Example 9-5, a dialog box with an OK button is created with the alert( ) method. For example, you can pop up a dialog box when the user clicks on a button:
<form action="test.php"> <input type="button" value="Pop a box" onclick="alert('Pop!');"> </form>
The onclick attribute causes the box to appear when the user clicks on the button.
It's also possible to create dialog boxes using the confirm( ) method that displays both an OK and Cancel button:
<script type="text/javascript"> if (confirm("Are you sure?")) alert("Great!"); else alert("What a pity!"); </script>
The confirm( ) method returns true when the user clicks Ok and false otherwise.
Another approach to producing output is to write to the browser window status line. However, this isn't a very effective mechanism: the status bar may be hidden or disabled, and it's easy to overlook messages displayed at the base of the window. Yet another approach is to create a new fully-featured non-dialog browser window, which we discuss later in this chapter. The final approach is to update values in input widgets, an approach we use later in our examples.
Loops and conditionals are almost the same in both languages. As discussed in Chapter 2, PHP has the for, while, foreach, and do...while loops, and the if and switch conditionals. JavaScript has the for, while, do...while, and for...in loops, and the if and switch statements. The continue and break statements are available in both languages.
The for, while, and do...while loops are the same in PHP and JavaScript, with the exception that in JavaScript it's possible to declare a variable in a for loop with the var statement; an example is shown in Example 9-5. JavaScript also has the for...in statement which allows you to iterate through properties of objects, while PHP has the foreach statement for iterating through elements in arrays. An example with the for...in statement is presented later in this section.
Functions are similar in PHP and JavaScript. Consider the following JavaScript example:
function bold(string) { document.writeln("<b>" + string + "</b>\n"); }
When called with the function call bold("this is bold"), the function prints the string <b>this is bold</b> as part of the document. Similarly to PHP, functions are declared with the statement function, parameters are listed in brackets and separated by commas, and the function body is surrounded by curly braces. Functions can optionally return values using the return statement, which behaves identically in PHP and JavaScript.
Variables that are declared within a function are local to that function. Local variables must be declared using the var statement as in the following example:
function count( ) { var x=1; while (x<6) { document.writeln(x + " "); x++; } }
Variables that are used or declared outside functions are global variables. Declaring globals with var is optional: as in PHP, they can be declared implicitly by assigning values to them. However, unlike PHP, global variables in JavaScript are accessible everywhere in the current document; global variables are not declared in functions using the global keyword.
JavaScript has two types of errors that report messages: load-time and run-time errors. Load-time errors are sometimes reported by the user agent before it runs the JavaScript, and you'll be shown a warning box that details the error, its line number, and the code fragment itself. Run-time errors occur when a code fragment is running and, again, a warning box is sometimes displayed with the line number of the code that caused the error.
The inconsistent nature of error reporting can be annoying: often, you'll get no messages at all but the script won't run. However, in many browsers (including Mozilla and Netscape), you can get more detailed error information by typing javascript: in the Location box and pressing Enter. The JavaScript console that pops up lists all errors that have occurred since the browser began running. You can remove old messages by clicking on the Clear button that's shown at the top of the console window; periodically doing this is a good way to avoid confusion about which errors are applicable to what.
Errors can also be annoying because they are often platform- or browser-dependent and change from one release to the next. Complex JavaScript adds a thicker client to a web database application, and this may reveal differences between browser applications, browser versions, and different platforms.
If complex JavaScript is required or desired, make sure it's tested on all the popular platforms with the popular browser products and versions. However, we recommend that JavaScript be kept simple: complex tasks should be left to PHP scripts, and you should ensure that user interfaces function correctly even if JavaScript is faulty or disabled.
Objects associated with the browser, windows, and the document are accessible in JavaScript. For example, in Example 9-5, the form object and its child (an input text widget) are accessed and used. Historically, the definition of these objects (and the events, properties, and methods described in the next sections) was part of the JavaScript standard and they were loosely known as the Navigator objects . This has now changed, and the objects are defined as part of the Document Object Model (DOM).
In this section, we informally describe the objects and properties that are accessible from within JavaScript, and avoid the details of DOM. However, the complete specification is accessible at http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/.
The window object is the top of the DOM hierarchy, and it contains the toolbars and menus of the browser, as well as the document and its sub-components. The hierarchy of the objects that descend from window is shown in Figure 9-2.
In JavaScript code, the document object can be referenced using the same notation as in PHP's object-oriented model using window.document, or just document for short (because there is only one window when you're not using frames, which we don't in this book).
Each of the objects in the hierarchy has properties and methods, and creates events. Properties are characteristics that describe the appearance of the object, while the methods are its behaviors. Events are actions that the object can act on such as mouse clicks or key presses. Events are discussed in the next section, and methods and properties in the following section. However, selected events, methods, and properties are used in examples here.
Consider a document that contains a form that has a text input widget and a submit button:
<form name="custform" method="GET" action="cust.php"> Surname: <input type="text" name="surname"> <br><input type="submit" name="submit"> </form>
The text widget is accessible using the names associated with the objects in the hierarchy. In this example, the form widget has the attribute name="custform", and the input widget has the attribute name="surname". You can therefore reference the text widget's value as document.custform.surname.value. The value is a property of the text input widget and it contains the data the user has entered, or it can be assigned a value to modify the data that's shown in the widget.
The value could be output when an onchange event is triggered in the widget itself:
<input type="text" name="surname" onchange="alert('You entered ' + document.custform.surname.value);">
The browser automatically generates an onchange event when the text in the widget changes; we explain events more later.
Alternatively, you could output the value when the submission process itself occurs:
<form name="custform" method="GET" action="cust.php" onsubmit="alert('You entered ' + document.custform.surname.value);">
Another way to access the properties of an object is to access the DOM element array. For example, the value of the text input widget in the custform can be referenced as:
document.forms[0].elements[0].value
The notation forms[0] means the first form in the document, and elements[0] means the first element of that form. You can iterate through all properties in an object using the for...in statement that we introduced previously. For example, to show the names of all elements in the form, use:
for (o in document.custform) string += o + ' '; alert("Here are the elements: " + string);
The loop assigns each element in document.custform in turn to the variable o, and then o is appended to string. If you include this fragment in a document containing the custform, you may be surprised that it outputs not just the surname widget and the submit button, but more than 50 properties. Some of these are discussed in the next section.
Some browsers are fussier than others. For example, Microsoft's Internet Explorer complains when you reference an object before it's defined. This means that you can't reference a form earlier in your HTML source than where the form is actually declared. You'll find that these kinds of issues make developing complex or portable code difficult. As we've already discussed, we recommend you use JavaScript for simple tasks and leave the complex ones to PHP on the server side.
In JavaScript, there are also several other pre-defined objects. These include core objects such as Array, RegExp, Date, and Math that are discussed in detail in the Core JavaScript Guide available from http://devedge.netscape.com/library/manuals/.
Events are triggered by both the user agent (usually a web browser), and the user working with the document and browser. These events are useful triggers for JavaScript actions. For example, a function might be called as a page loads, when the user presses the submit button, when a form field changes, or when the mouse passes over a document element. Examples using many of these events are included in later examples in this chapter.
The key events that can be trapped and handled by JavaScript are as follows:
When a user removes focus from form elements or a window. This occurs when the user presses the Tab key to move to the next widget, clicks on another widget or window, or carries out some other action that takes the focus away from the current window or widget.
When a select, text, or textarea input loses focus and has been modified since it gained focus.
When a pointing device (usually a left mouse button) clicks on an area, button, checkbox, hypertext link, radio button, reset, or submit.
When a user brings focus to form elements or a window, normally by clicking in it.
When a user agent finishes loading a window (or all frames in a frameset).
When the pointing device moves out from an element, area, or hypertext link.
When the pointing device moves over an element, area, or hypertext link.
When a form is reset.
When a form is submitted.
When the user exits a page, that is, when the user agent unloads the document from the window. For example, this happens when a new page is loaded, a browser window or tab is closed, or the browser program ends.
We have omitted other events related to key presses and text selection, as well as other types of mouse clicks and movements. These are detailed in the HTML 4.01 documentation at http://www.w3.org/TR/html4/interact/scripts.html. and in the DOM documentation listed in the previous section.
The window, document, form, and input element objects have properties and methods that are commonly accessed and used in validation tasks. This section lists selected methods and properties, and examples later in this chapter show many of these used in scripts. Images, tables, the document body, document styles, and frames also have their own methods and properties, but we don't discuss these here. The complete list of objects, methods, and properties can be found at http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/ecma-script-binding.html.
The navigator object is outside of the window hierarchy we showed in Figure 9-2 and the standards. However, it is useful because it describes the browser environment. Its properties include:
The operating system.
The same information as sent in the HTTP request that includes the user agent name and version.
The window object properties and methods include:
The URL in the location box.
The window's name. Can be used to retrieve or set the window name. For example, window.name = "Hello!" sets the title to Hello!.
Determines whether the location bar is visible. It can be set to true or false, making the location bar visible or hidden respectively.
Determines whether the menu bar is visible. It can be set to true or false, making the menu bar visible or hidden respectively.
Determines whether the personal or directories bar is visible. It can be set to true or false, making the personal bar visible or hidden respectively.
Determines whether the horizontal and vertical scroll bars are visible. It can be set to true or false, making the scroll bars visible or hidden respectively.
Determines whether the status bar is visible. It can be set to true or false, making the status bar visible or hidden respectively.
Determines whether the toolbar is visible. It can be set to true or false, making the toolbar visible or hidden respectively. It can be set or unset only before the window is opened.
The text displayed in the status bar at the base of window. This can be set to display a message to the user.
Shows a dialog box with an OK button, and takes text as a parameter.
Causes the user agent to return to the previous resource in its history list. This has the same effect as pressing the Back button in the web browser.
Closes the current window.
Shows a dialog box with OK and Cancel buttons, and takes text as a parameter. Returns true when the user presses OK and false otherwise.
Causes the user agent to go forward to the next resource in its history list. This has the same effect as pressing the Forward button in the web browser.
Opens a new window, taking a URL, name, and features as parameters.
Sends the contents of the window to a printer.
Shows a dialog box with an input widget and OK and Cancel buttons. Takes a text question to display, and optional default text to display in the input widget. Returns true when the user presses OK and false otherwise.
The document object properties and methods include:
The date the resource was last modified.
The text contained in the <title> tag of the document.
The URL of the current document.
Writes text to the current document during its creation. The latter adds a carriage return character to the string.
The form objects in a document include the following properties and methods:
The value of the name attribute.
The value of the action attribute.
The value of the method attribute (GET or POST).
Sends the form to the server.
Clears all user-entered input from the form. If the form was shown with pre-filled values, it is reset to those values. If the form was initially empty, it is reset to empty.
The form elements select, textarea, input, and button have common methods and properties that include:
The type of input as defined by the type attribute in the form element.
The value contained or selected in the form element.
The length of the value contained or selected in the form element.
The value of the name attribute in the form element.
Brings the focus to the form element (not used with button elements).
Removes the focus from the form element (not used with button elements).
Selects (usually by highlighting) the text in an input or textarea element (not used with select or button elements).
Returns the character in the value at the position of the integer parameter. For example, value.charAt(0) returns the first character in the value.
The short examples in this section implement simple, common, and useful JavaScript web database application features that use the techniques we have discussed so far. These include:
Checking if two passwords are the same
Mouse rollovers, where an image is changed to highlight an option as the mouse cursor passes over it
Calculating and updating form fields based on user changes to data
Interacting with the web browser and windows to trigger events and manipulate presentation
Detecting the browser application and version
Drop-down menus that load a new URL into the current window
Example 9-6 is an example of JavaScript validation that checks whether a password is the same when the user enters it twice. The validation is interactive: an onchange event is trapped for the two password widgets, formPassword1 and formPassword2, and the function thesame( ) is called whenever the user changes the data in a widget and then leaves it. The error reporting is field-by-field.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Password Validation</title> <script type="text/javascript"> <!-- Hide the script function thesame(value1, value2) { if (((value1 != null) || (value1 != "")) && value2 != "" && value1 != value2) { alert("The passwords must be identical."); return (false); } return (true); } // end hiding --> </script> </head> <body> <h1>Username Form</h1> <form method="post" action="test.php" name="userForm"> <br>Username: <input type="text" name="userName" size=10> <br>Password: <input type="password" name="formPassword1" size=10 onchange="thesame(document.userForm.formPassword1.value, document.userForm.formPassword2.value);"> <br>Re-enter password: <input type="password" name="formPassword2" size=10 onchange="thesame(document.userForm.formPassword2.value, document.userForm.formPassword1.value);"> <br><input type="submit" value="SUBMIT"> </form> </body> </html>
The function thesame( ) checks if the current widget contains data. If it does, and the other password widget also contains data, the data in the two widgets is compared. If the data in the widgets is different, an error message is shown to the user. It's necessary to test whether both widgets actually contain data in interactive validation; without this check, the function annoyingly displays an error before the user has the opportunity to enter data into both widgets.
Example 9-7 shows a basic implementation of the common rollover feature used in many web applications.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>MouseOver Example</title> </head> <body bgcolor="#ffffff"> <a href="add_to_cart.php" onmouseout="cart.src='cart_off.jpg'" onmouseover="cart.src='cart_on.jpg'"> <img src="cart_off.jpg" border=0 name="cart" alt="cart picture"></a> </body> </html>
When the page is first loaded, an un-highlighted image of a shopping cart is shown; the image is used in the front page of the winestore in Chapter 16. The image is loaded with the HTML fragment:
<img src="cart_off.jpg" border=0 name="cart">
The only difference to the usual approach of loading images is that the <img> tag has the attribute name="cart".
If the mouse passes over the cart image, an onmouseover event is triggered, and the JavaScript action carried out is:
onmouseover="cart.src='cart_on.jpg'"
The event handler changes the value of the src attribute of the <img> tag with the name="cart". The result is that a new highlighted image is loaded to replace the un-highlighted image. In the case of our winestore, a shopping cart with a blue foreground is shown.
When the mouse leaves the image region, the onmouseout event is generated and handled with the following JavaScript fragment:
onmouseout="cart.src='cart_off.jpg'"
This restores the original image. The impression to the user is that the cart element is highlighted as the user focuses on the element.
Rollovers are straightforward to develop and the approach we've shown you works in all graphical browsers. You can even use the same technique to highlight menu options, and to produce pop-up and pull-down menus.
Another common use of JavaScript is to pre-fill a form with data from a calculation. Example 9-8 shows how data can be managed and updated in a shopping cart.
When the user changes the quantity of a wine he intends to purchase, an onchange event is generated. This change event is handled by the update( ) function, which modifies the value attribute of the total widget, showing the new total cost to the user. The new value shown to the user is calculated by multiplying together the quantity.value and the unit.value. Of course, as in all web database applications, the values and mathematics should be rechecked at the server when the form is submitted to the server.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Dynamic Form Update Example</title> </head> <body> <h1>Your Shopping Cart</h1> <form method="get" action="test.php"> <table border="0" width="100%" cellpadding="0" cellspacing="5"> <tr> <td>Quantity </td> <td>Wine</td> <td>Unit Price</td> <td>Total</td> </tr> <tr> <td><input type="text" name="quantity" value="1" size=3 onchange="total.value = unit.value * quantity.value;"> <td>1997 Anderson and Sons Wines Belcombe Grenache</td> <td>$<input type="text" value="17.29" name="unit" readonly></td> <td>$<input type="text" value="17.29" name="total" align="right" readonly></td> </tr> </table> <input type="submit" value="Purchase Wines"> </form> </body> </html>
Example 9-9 shows four examples of handlers for buttons that use the methods defined for the window object. The method window.close( ) closes the focused window, window.print( ) shows the print dialog window, window.back( ) goes back one page, and window.open( ) opens a new browser window.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Playing with the Browser and Windows</title> </head> <body> <h1>Playing with the Browser and Windows</h1> <form action="example.9-6.php"> <input type="button" value="Close Window" onClick="window.close( );"> <br><input type="button" value="Print Window" onClick="window.print( );"> <br><input type="button" value="Go Back" onclick="window.back( );"> <br><input type="button" value="Visit the book site" onClick="window.open('http://www.webdatabasebook.com/','BookSite', 'toolbar=yes,location=yes,menubar=yes,directories=yes,scrollbars=yes, resizable=yes');"> </form> </body> </html>
Only window.open( ) is complex. The first parameter is the URL to request in the new window, the second is a title, and the third is a set of properties of the new window. Without the list of properties that are included, the default new window has no Location box, no toolbars, no scrollbars, and can't be resized.
As discussed previously, even simple JavaScript sometimes highlights annoying differences in the way browsers support standard features. Indeed, even different versions of the same browsers support different JavaScript features from the same version of the standard.
Example 9-10 shows how the browser application name and version can be detected with both JavaScript and PHP. If a JavaScript script requires customization for a particular product, if statements can carry out actions in different ways. Another common approach in JavaScript-intensive web database applications is to write two sites: one that uses Internet Explorer JavaScript (known as Jscript), and another that uses Netscape Navigator or Mozilla JavaScript. However, as we recommended earlier, complex JavaScript is often best avoided in favor of server-side scripts.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <title>Playing with the Browser and Windows</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <script type="text/javascript"> <!-- Hide the script from old browsers alert("You are using " + navigator.userAgent); // end the hiding --> </script> This page should pop up a box if you have a JavaScript-capable and enabled browser. <br>But, using PHP, we can tell you that you're using the <?php print $_SERVER["HTTP_USER_AGENT"]; ?> browser. </body> </html>
A common use of JavaScript is to automatically load a new page when a user selects a menu option from a drop-down list. Example 9-11 shows how to do this using a select widget and its properties. The JavaScript in the body of the document is straightforward: when the user changes their selection of menu item, an onchange event is triggered, and the loadNewPage( ) function is called.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Menu Example</title> <script type="text/javascript"> <!-- function loadNewPage( ) { var listItem = document.menuForm.newPage.selectedIndex; var newPage = document.menuForm.newPage.options[listItem].value; location.href = newPage; } //--> </script> <body> Where do you want to go now? <br><form method="GET" action="menus.html" name="menuForm"> <select name="newPage" onchange="loadNewPage( );"> <option value="menus.html">This page <option value="http://www.webdatabasebook.com/">The book web site <option value="http://www.oreilly.com/">O'Reilly and Associates <option value="http://www.hughwilliams.com/">Hugh's homepage <option value="http://www.mds.rmit.edu.au/~dave/">Dave's homepage </select> </form> </body> </html>
The form in Example 9-11 has a name attribute of menuForm and the select list has a name attribute of newPage. Therefore, the list is referenced as document.menuForm.newPage. The loadNewPage( ) function references the list to load the new page in three steps:
The local variable listItem is assigned the ordinal number of the selected value from the list. To discover which item is selected, the selectedIndex property of the newPage <select> is inspected. For example, if the first item is selected then the value is 0.
The value of the selected item (which contains the new URL) is determined by accessing the options array property of the list and retrieving the value of the element listItem. This value is stored in the local variable newPage. For example, if the first item in the list is selected listItem is 0, the value is the URL http://www.webdatabasebook.com/, and newPage is set to that value.
To load the new URL in the current window, the location.href property is set to newPage. This causes the new document to load.
The example in this section shows how JavaScript can be used as a validation tool across multiple HTML pages or templates. An example of errors produced by applying the techniques described in this section to customer validation is shown in Figure 9-3. We show you the JavaScript code, the PEAR IT template, and the PHP code in this section.
The general-purpose verify( ) function for post-validation and field-by-field error reporting is shown in Example 9-12. The code is stored in the file example.9-12.js and is designed to be added to a template, such as the phonebook template developed in Chapter 8. Later in this section, we show you how to add it to a customer details template that has diverse validation needs.
By storing JavaScript code in its own file, it can be reused across multiple HTML pages or templates. To do this, instead of including code between the <script> and </script> tags, you add a src attribute to the <script> element that specifies the file that contains the JavaScript code. For example, to load the code in Example 9-12 into a document or template, you use:
<script type="text/javascript" src="example.9-12.js"> </script>
This approach saves cutting and pasting the code into more than one file, and avoids the need to update several pages when the script changes. It also has the additional advantage of reducing network traffic if the user has a web browser cache, because a copy of the script can be reused in multiple HTML pages without retrieving it again from the web server.
// A utility function that returns true if a string contains only // whitespace characters. function isblank(e) { if (e.value == null || e.value == "") return true; for(var i = 0; i < e.value.length; i++) { var c = e.value.charAt(i); if ((c != ' ') && (c != '\n') && (c != '\t')) return false; } return true; } // Checks if an optional field is blank function checkblank(e) { if (isblank(e)) { alert("The field " + e.description + " must be filled in."); return false; } return true; } // Checks if a field is numeric. // If the optional min property is set, it checks it is greater than // its value // If the optional max property is set, it checks it is less than // its value function checknumber(e) { var v = parseFloat(e.value); if (isNaN(v)) { alert("The field " + e.description + " must be a number"); return false; } if ((e.minNumber != null) && (v < e.minNumber)) { alert("The field " + e.description + " must be greater than or equal to " + e.minNumber); return false; } if (e.maxNumber != null && v > e.maxNumber) { alert("The field " + e.description + " must be less than or equal to " + e.maxNumber); return false; } return true; } // Checks if a field looks like a date in the 99/99/9999 format function checkdate(e) { var slashCount = 0; if (e.value.length != 10) { alert(" The field " + e.description + " must have the format 99/99/9999" + " and be 10 characters in length"); return false; } for(var j = 0; j < e.value.length; j++) { var c = e.value.charAt(j); if ((c == '/')) slashCount++; if (c != '/' && (c < '0' || c > '9')) { alert(" The field " + e.description + " can contain only numbers and forward-slashes"); return false; } } if (slashCount != 2) { alert(" The field " + e.description + " must have the format 99/99/9999"); return false; } return true; } // Checks if a field contains any whitespace function checkwhitespace(e) { var seenAt = false; for(var j = 0; j < e.value.length; j++) { var c = e.value.charAt(j); if ((c == ' ') || (c == '\n') || (c == '\t')) { alert("The field " + e.description + " must not contain whitespace"); return false; } } return true; } // Now check for fields that are supposed to be emails. // Only checks that there's one @ symbol and no whitespace function checkemail(e) { var seenAt = false; for(var j = 0; j < e.value.length; j++) { var c = e.value.charAt(j); if ((c == ' ') || (c == '\n') || (c == '\t')) { alert("The field " + e.description + " must not contain whitespace"); return false; } if ((c == '@') && (seenAt == true)) { alert("The field " + e.description + " must contain only one @"); return false; } if ((c == '@')) seenAt = true; } if (seenAt == false) { alert("The field " + e.description + " must contain one @"); return false; } return true; } // This is the function that performs <form> validation. // It is invoked from the onSubmit( ) event handler. // The handler should return whatever value this function // returns. function verify(f) { // Loop through the elements of the form, looking for all // text and textarea elements. Report errors using a post validation, // field-by-field approach for(var i = 0; i < f.length; i++) { var e = f.elements[i]; if (((e.type == "text") || (e.type == "textarea"))) { // first check if the field is empty and shouldn't be if (!e.isOptional && !checkblank(e)) return false; // Now check for fields that are supposed to be numeric. if (!isblank(e) && e.isNumeric && !checknumber(e)) return false; // Now check for fields that are supposed to be dates if (!isblank(e) && e.isDate && !checkdate(e)) return false; // Now check for fields t