|only for RuBoard - do not distribute or recompile|
Validation of <form> data, the main topic of this section.
Customizing the browser and using information from the browser to enhance presentation.
Client-side validation 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. Moreover, client-side validation can be implemented as interactive validation, not only as post-validation, as on the server side. However, validation in the client tier is unreliable: the user can bypass the validation through design, error, or configuration. For that reason, client-side validation is a tool that should be used only to improve speed, reduce load, and add features, and never to replace server-side validation.
This example is designed to check if a 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 7-1.
The function call is part of the <form> element:
<form onSubmit="return(containsblanks(this.userName));" method="post" action="test.php">
When the submission event occurs—the user presses the Submit button—the onSubmit action handler is triggered. In this case, the function containsblanks( ) is called with one parameter, this.userName. The object this refers to the <form> itself and the expression this.userName refers to 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.
A for loop repeatedly performs actions on 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 stored in a character variable c. s.value.charAt(i) is again an expression related to the value entered by the user in the <form>. The value attribute of the widget has an associated function (or, more correctly, a method) called 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( ) function is called with an error string as a parameter. The alert( ) function presents a dialog box in the browser that shows the error message and has an OK button, as shown in Figure 7-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.
A sophisticated and general-purpose data entry function for post-validation and batch error reporting is shown in Example 7-2. Only part of the script is shown; the remainder of the script includes the same PHP code to retrieve data and the HTML to display the customer <form> as in Example 6-7 in Chapter 6.
In the example, the <form> tag contains a long script for the onSubmit event that is called when the user clicks the Submit button. The code creates and sets properties for each data entry widget. As all widgets are mandatory, a description property is created and set (e.g., this.email.description = 'Email'). This description is later displayed in an error dialog box if data isn't entered. For widgets that are optional—there are none in this example, but the full customer <form> in Chapter 10 has them—an optional = true property can be set.
For widgets that require specific validation, a property that describes the data type is set. For example, the email widget has a property of this.email.email = true to ensure that validation appropriate to an email field is performed. After setting all properties for all fields, the verify( ) function is called with the <form> (this refers to the <form>) object as a parameter; the <form> object includes all widgets and their properties.
For compactness, we don't describe in detail how the verify( ) function works. However, it has the following features:
The function progressively creates a message to display to the user—much like $errorString in the PHP validation—as errors are detected. After collecting all errors, an error dialog box is shown listing all errors the user needs to correct before the <form> will submit. An example of the error dialog box is shown in Figure 7-2.
All widgets that are inputs of type text or textarea and aren't optional are checked to ensure they contain data.
Numeric fields are checked to ensure they are actually numeric and, if the value must fall in a range, the value is checked to ensure it's within the range.
Dates are checked to ensure they are in the DD/MM/YYYY format used in most countries.
Fields that should not contain whitespace are checked to ensure they don't contain spaces, tabs, or carriage returns.
The verify( ) function isn't comprehensive and certainly doesn't do all the validation proposed for the winestore customer <form>. However, in most cases, the customer <form> can't be submitted without a good chance of it passing the server-side validation checks.
This approach has the 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.
The function thesame( ) checks if the current widget contains data. If it does, the data in the widget is compared to the data in the other password widget. 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.
There are several other events that are commonly trapped and handled in validation:
When a user removes focus from a <form>, <frame>, or window
Left mouse button click on a <form> element
When a user brings focus to a <form>, <frame>, or window
When the user exits a page
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 which browser application and version the user is using
Example 7-4 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> <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 image of a shopping cart in plain gray off-mode is shown; the image is used in the front page of the winestore. As usual, 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 a name attribute, in this case name="cart".
The event handler changes the value of the src attribute of the <img> tag with the name="cart". The result is that a new image is loaded to replace the off-mode image with an on-mode image. In this case, a shopping cart with a blue foreground is shown.
This restores the original gray off-mode image. The impression to the user is that the cart element is highlighted as the user focuses on the element; the same technique is used to highlight menu options and to produce pop-up and pull-down menus.
When the user changes the quantity of 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.
Having said that, adding features that are helpful is desirable. Example 7-6 shows four examples of handlers for buttons that use methods or functions defined for the browser window object. The function window.close( ) closes the focused window, window.print( ) shows the print dialog window, windows.history.go(-1) goes back one page, and window.open( ) opens a new browser window.
The page rendered in a Netscape browser is shown in Figure 7-4.
Only window.open( ) has any complexity. 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 the new window has. 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: it's an evil console!
|only for RuBoard - do not distribute or recompile|