All Categories :
JavaScript
Chapter 7
Form Validation
CONTENTS
When a user enters data into the fields of a form in your Web
page, it's entirely possible that the data might not make sense.
The user may enter a numeric value that is too low or too high.
The user may enter text where you expect a number, or vice versa.
The user may misspell text. The user may skip a required field.
There are probably as many ways to enter invalid data as there
are ways to write forms.
It should not come as a surprise, then, that an important step
in creating a form is making sure that what the user entered makes
sense. That step is called form validation.
Creating a form that validates input-regardless of whether you
use JavaScript-requires a CGI (Common Gateway Interface) program
on the server. The Web page is only a front end to the server.
Suppose your boss has asked you to create a Web page from which
customers can order computer equipment. You need to collect the
customer's name, address, phone number, age, credit card information,
and what the customer wants to order.
The customer must have a first and last name; a middle initial
is optional. The customer must have a street address. The customer
must reside in the United States and must provide either a 5-digit
zip code or a 5+4 zip code. The customer must supply a daytime
phone number, including area code. The customer must provide his
or her age, and must be at least 18. The customer must supply
a credit card number, credit card type (Visa or MasterCard), and
date of expiration.
The customer may order any of the following: HAL-470 computer
($2,000), Banana9000 computer ($3,000), high-resolution monitor
($800), low-resolution monitor ($50), deluxe keyboard ($250),
regular keyboard ($40), laser printer ($2,000), inkjet printer
($600), dot-matrix printer ($200), mouse ($100), trackball ($125),
or scanner ($500). The customer may not order more than $5,000
worth of equipment.
To create a Web page form, you must first choose the kinds of
input fields you need. To capture the customer's name, INPUT TEXT
elements are the obvious choice. Let's make the first and last
names 20 characters each and the middle initial 1 character.
The address is next. A TEXTAREA element, 2 rows of 30 characters
each, will suffice for the street address, and INPUT TEXT elements
will work for the city, state, and zip codes-20 characters for
the city, 2 characters for the state, and 10 for the zip code.
For the customer's daytime phone number, use three INPUT TYPE
elements-three characters for the area code, three characters
for the office code, and four characters for the remainder of
the phone number.
A three-character INPUT TEXT element will suffice for the customer's
age-we could get an order from someone older than 99.
The credit card information is easy: Four INPUT TEXT elements
for the credit card number, four characters each; an INPUT RADIO
element to select between Visa and MasterCard; and two INPUT TEXT
elements for the expiration date, two characters each.
You'll need a SELECT element for the merchandise, and it has to
allow for multiple selections.
Finally, you'll need an INPUT SUBMIT element to send the data
to the server, and an INPUT RESET element to allow the customer
to start over.
Putting it all together, you have a Web page. Listing 7.1 shows
the HTML and Figure 7.1 shows you what the form looks like on
the screen.
Figure 7.1 : Non-JavaScript solution.
Listing 7.1: Non-JavaScript solution
<HTML>
<HEAD>
<TITLE>ComputoRama Order Form</TITLE>
</HEAD>
<BODY>
<FORM ACTION="mailto:mailhost@computoRama.usa.com" METHOD=POST>
<TABLE BORDER="2" CELLPADDING="1">
<TR>
<TD ROWSPAN="2">Who Are You?</TD>
<TD><INPUT TYPE="text" NAME="FirstName" SIZE=2Ø></TD>
<TD><INPUT TYPE="text" NAME="MiddleInitial" SIZE=1></TD>
<TD><INPUT TYPE="text" NAME="LastName" SIZE=2Ø></TD>
<TD><INPUT TYPE="text" NAME="Age" SIZE=3></TD>
</TR>
<TR>
<TD><FONT SIZE="-2">First Name</FONT></TD>
<TD><FONT SIZE="-2">MI</FONT></TD>
<TD><FONT SIZE="-2">Last Name></TD>
<TD><FONT SIZE="-2">Age</TD>
</TR>
<TR>
<TD ROWSPAN="3">How Do We Contact You?</TD>
<TD COLSPAN="4" VALIGN="TOP">Street Address: <TEXTAREA
name="StreetAddress" rows=2 cols=3Ø></TEXTAREA></TD>
</TR>
<TR>
<TD COLSPAN="2">City: <INPUT TYPE="text" NAME="City"
SIZE=2Ø></TD>
<TD COLSPAN="2">State: <INPUT TYPE="text" NAME= "State"
SIZE=2></TD>
</TR>
<TR>
<TD COLSPAN="2">ZIP Code: <INPUT TYPE="text" NAME="ZIPCode"
SIZE=1Ø></TD>
<TD COLSPAN="2">Daytime Phone
(<INPUT TYPE="text" NAME="Phone1" SIZE=3>)
<INPUT TYPE="text" NAME="Phone2" SIZE=3>-
<INPUT TYPE="text" NAME="Phone3" SIZE=4></TD>
</TR>
<TR>
<TD>Credit Card
<INPUT TYPE="radio" NAME="CreditCardType" VALUE="Visa"
CHECKED>Visa
<INPUT TYPE="radio" NAME="CreditCardType"
VALUE="MasterCard">M/C</TD>
<TD COLSPAN="2" ALIGN="CENTER">
<INPUT TYPE="text" NAME="CreditCardNumber1" SIZE=4>
<INPUT TYPE="text" NAME="CreditCardNumber2" SIZE=4>
<INPUT TYPE="text" NAME="CreditCardNumber3" SIZE=4>
<INPUT TYPE="text" NAME="CreditCardNumber4" SIZE=4></TD>
<TD COLSPAN="2">Expiration Date:
<INPUT TYPE="text" NAME="ExpirationMonth" SIZE=2>/
<INPUT TYPE="text" NAME="ExpirationYear" SIZE=2></TD>
</TR>
<TR>
<TD>Merchandise</TD>
<TD COLSPAN=4><SELECT MULTIPLE NAME="Merchandise" SIZE=1>
<OPTION SELECTED> HAL-47Ø <OPTION> Banana9ØØØ
<OPTION> High Res Monitor <OPTION> Low Res Monitor
<OPTION> Deluxe Keyboard <OPTION> Regular Keyboard
<OPTION> Laser Printer <OPTION> Inkjet Printer <OPTION>
Dot Matrix Printer
<OPTION> Mouse <OPTION> Trackball
<OPTION> Scanner
</SELECT></TD>
</TR>
<TR>
<TD ALIGN=CENTER COLSPAN="5">
<H1>Thank You For Your Order!</H1>
</TD>
</TR>
</TABLE>
<CENTER>
<INPUT TYPE="submit" VALUE="Ship It!"> <INPUT TYPE="reset"
VALUE="Clear Entries">
</CENTER>
</FORM>
</BODY>
</HTML>
The rest of the solution resides on the server, and is beyond
the scope of this book. There will be a CGI (Common Gateway Interface)
program on the server that will process the results when the customer
presses the Ship It! button. That program will have to perform
form validation and return an error to the customer if mandatory
fields are omitted or mistyped. That is in addition to whatever
work must be performed to process a valid order.
Using JavaScript, you can enhance the form shown in Figure 7.1
to perform much of the form validation on the customer's browser.
The advantages of doing so are
- Better performance for the customer. Data entry errors will
be caught much more quickly by the JavaScript code than by the
CGI program on the server. (It takes time to transmit the data
to the server, and CGI programs are not, as a rule, any faster
than JavaScript programs.) Feedback to the customer is nearly
instantaneous. If there are no errors, the CGI program, which
now has less error-checking to do, will process the order more
quickly.
- Better performance for the server. Because more errors are
caught locally, there is less traffic to and from the server.
The CGI program does not have to be as complicated and should
execute more quickly, which decreases the load on the server.
The system can handle more orders than it could when the server
CGI program had to proofread the forms.
So what can you do to add form validation to this Web page? Plenty.
First, get rid of the SUBMIT button. You can write an event handler
to catch the submit event, and that event handler can prevent
submission of the form. However, whether the customer's data is
transmitted or not, the page will be cleared. If you make the
SUBMIT button an ordinary BUTTON INPUT element and give it an
ONCLICK event handler, you'll have better control over the screen.
All the ONCLICK event handler has to do is perform the form validation
and, if all the customer data is acceptable, call document.forms[0].submit().
Having created an event handler to perform forms validation, let's
start with the customer's name. Recall that the customer must
supply a first and last name. To verify this, you simply need
to check that the fields have a nonzero length, like this:
function nameOK()
{
if (document.forms[ Ø ].FirstName.value.length == Ø)
{
alert("I need a first name, please");
return false;
}
if (document.forms[ Ø ].LastName.value.length == Ø)
{
alert("I need a last name, please");
return false;
}
return true;
}
Then, in your "submit" button event handler, call the
function:
function checkForm()
{
if (nameOK() == false)
{
return;
}
// other tests...
document.forms[ Ø ].submit();
}
The age field has to be filled in, and the age must be a number
greater than or equal to 18. First, verify that the customer has
entered anything. Then verify that the customer has entered a
number: Use the substring method to get the first character in
the field and verify that it is a digit. For that, you need a
little routine:
function isDigit(c)
{
var test = "" + c;
if (test == "Ø" || test == "1" || test == "2" || test == "3" || test == "4"
|| test == "5" || test == "6" || test == "7" || test == "8" || test == "9")
{
return true;
}
return false;
}
Finally, having verified that the customer entered something that
starts with a digit, use the built-in function parseInt() to convert
the customer's input and verify that the value is at least 18.
Putting these steps together, you have something like this:
function ageOK()
{
if (document.forms[ Ø ].Age.value.length == Ø)
{
alert("Sorry, you have failed to enter an age");
return false;
}
var c = document.forms[ Ø ].Age.value.substring(Ø, 1);
if (isDigit(c) == false)
{
alert("Sorry, you have failed to enter an appropriate age");
return false;
}
var result = parseInt(document.forms[ Ø ].Age.value, 1Ø);
if (result < 18)
{
alert("Sorry, you have failed to enter an appropriate age");
return false;
}
return true;
}
As with NameOK(), you then add this to the checkForm() function:
function checkForm()
{
if (nameOK() == false)
{
return;
}
if (AgeOK() == false)
{
return;
}
// other tests...
document.forms[ Ø ].submit();
}
Now that the customer's name and age have been verified as present
and acceptable, it's time to verify the address. Verifying the
presence of the street address, city, and state fields is exactly
like verifying the presence of the first and last name fields:
Just check for a nonzero length of the field's value property.
The zip code is a little more interesting, however. Recall that
the zip code must be either a five-digit code or ZIP+4-5 digits,
a hyphen, and four digits.
Because this is something you're going to do more than once, let's
write a function to verify that a given string is composed entirely
of digits. It should simply extract the characters from the string
one by one and verify that each one is a digit:
function isAllDigits(s)
{
var test = "" + s;
for (var k = Ø; k < test.length; k++)
{
var c = test.substring(k, k+1);
if (isDigit(c) == false)
{
return false;
}
}
return true;
}
Then checking the zip code field is easy. First, check the length
of the field value-it should be either 5 or 10. If the length
is 5, call isAllDigits() for the value. If it's 10 digits, use
the substring method to get the first 5 characters and verify
that they're all digits. If they are, check the next character-it
should be a hyphen-and then use the substring method to get the
last four characters. Check that they're all digits as well. The
function should look like this:
function zipOK()
{
var zip = document.forms[ Ø ].ZIPCode.value;
if (zip.length == 5)
{
var result = isAllDigits(zip);
if (result == false)
{
alert("Invalid character in zip code");
}
return result;
}
else if (zip.length == 1Ø)
{
var result = isAllDigits(zip.substring(Ø,5));
if (result == true)
{
if (zip.substring(5,6) != "-")
{
result = false;
}
else
{
result = isAllDigits(zip.substring(6,1Ø));
}
}
if (result == false)
{
alert("Invalid character in zip code");
}
return result;
}
else
{
alert("Invalid zip code; please re-enter it");
return false;
}
}
Checking the phone number is now very easy. You simply verify
that all three fields are filled in and that they're all digits.
Checking the credit card numbers is also easy; just verify that
there are four digits in each of the four fields. But you can
take it a step further. Most credit card numbers can be validated
by using a rule called MOD 10, and for a given company, there
is usually a fixed prefix or range of prefixes for the card number.
All Visa card numbers begin with 4, and all MasterCard card numbers
begin with 51, 52, 53, 54, or 55, and both numbers can be validated
with the MOD 10 rule.
The MOD 10 rule says to scan the card number from right to left.
Starting with the digit on the right, double every other digit
as you move to the left. For the number 49927398716, this means
you wind up with these numbers: 4 (9+9) 9 (2+2) 7 (3+3) 9 (8+8)
7 (1+1) 6, or 4 18 9 4 7 6 9 16 7 2 6. Doubled numbers that become
2-digit values are then replaced with the sum of the digits: 4
(1+8) 9 4 7 6 9 7 (1+6) 2 6, or 4 9 9 4 7 6 9 7 7 2 6. These digits
are then added up; the sum should be evenly divisible by 10 (in
this case, they add up to 70-the number passes).
Applying the MOD 10 rule to our credit card numbers means that
the first and third digits of each set of four digits needs to
be doubled. Rather than manipulate the digits of the result, you
can write a function to get the doubled and digit-summed value
of a given digit:
function doubleForMod1Ø(c)
{
var d = Ø + c;
if (d == Ø) return Ø;
if (d == 1) return 2;
if (d == 2) return 4;
if (d == 3) return 6;
if (d == 4) return 8;
if (d == 5) return 1; // 5+5 = 1Ø; 1+Ø = 1
if (d == 6) return 3; // 6+6 = 12; 1+2 = 3
if (d == 7) return 5; // 7+7 = 14; 1+4 = 5
if (d == 8) return 7; // 8+8 = 16; 1+6 = 7
return 9; // (digit must be 9) 9+9 = 18; 1+8 = 9
}
Then, for the entire four digits, obtain the sum:
function sumForMod1Ø(s)
{
var v = parseInt(s, 1Ø); // get the value
var result = doubleForMod1Ø(Math.floor(v / 1ØØØ));
v = v % 1ØØØ;
result += Math.floor(v / 1ØØ);
v = v % 1ØØ;
result += doubleForMod1Ø(Math.floor(v / 1Ø));
v = v % 1Ø;
result += v;
return result;
}
Putting all this together, let's validate the credit card number
using the code shown in Listing 7.2.
Listing 7.2: The validateCreditCardNumber() function
function validateCreditCardNumber()
{
if (document.forms[ Ø ].CreditCardNumber1.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (document.forms[ Ø ].CreditCardNumber2.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (document.forms[ Ø ].CreditCardNumber3.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (document.forms[ Ø ].CreditCardNumber4.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber1.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber2.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber3.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber4.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (document.forms[ Ø ].CreditCardType[ 1 ].checked == true) // Visa
{
if (document.forms[ Ø ].CreditCardNumber1.value.substring(Ø,1) != "4")
{
alert("The credit card number is not valid; please re-enter it");
return false;
}
}
else // must be MasterCard
{
var prefix =
parseInt(document.forms[Ø].CreditCardNumber1.value.substring(Ø,2));
if (prefix < 51 || 55 < prefix)
{
alert("The credit card number is not valid; please re-enter it");
return false;
}
}
var sum = sumForMod1Ø(document.forms[ Ø ].CreditCardNumber1.value);
sum += sumForMod1Ø(document.forms[ Ø ].CreditCardNumber2.value);
sum += sumForMod1Ø(document.forms[ Ø ].CreditCardNumber3.value);
sum += sumForMod1Ø(document.forms[ Ø ].CreditCardNumber4.value);
if (sum % 1Ø != Ø)
{
alert("The credit card number is not valid; please re-enter it");
return false;
}
return true;
}
Verifying the expiration date is straightforward. Make sure the
month and year fields are filled in (make sure they have nonzero
lengths). Make sure month is a value from 1 to 12. Make sure month
and year are at least a month in the future. Listing 7.3 shows
how it works.
Listing 7.3: The dateOK() function
function dateOK()
{
if (document.forms[ Ø ].ExpirationMonth.value.length == Ø)
{
alert("You must fill in the expiration date");
return false;
}
if (isDigit(document.forms[ Ø ].ExpirationMonth.value.substring(Ø,1)) ==
false)
{
alert("Expiration date should be numeric");
return false;
}
var eMonth = parseInt(document.forms[ Ø ].ExpirationMonth.value, 1Ø);
if (eMonth < 1 || 12 < eMonth)
{
alert("Expiration date is out of range");
}
if (document.forms[ Ø ].ExpirationYear.value.length == Ø)
{
alert("You must fill in the expiration date");
return false;
}
if (isDigit(document.forms[ Ø ].ExpirationYear.value.substring(Ø,1)) == false)
{
alert("Expiration date should be numeric");
return false;
}
var eYear = parseInt(document.forms[ Ø ].ExpirationYear.value, 1Ø);
if (eYear < 5Ø)
{
eYear += 2ØØØ;
}
else
{
eYear += 19ØØ;
}
var today = new Date(); // get today's date
var thisYear = 19ØØ + today.getYear();
var thisMonth = 1 + today.getMonth();
if (eYear < thisYear)
{
alert("Your credit card seems to have expired");
return false;
}
if (thisYear < eYear)
{
return true;
}
if (eMonth < thisMonth)
{
alert("Your credit card seems to have expired");
return false;
}
if (thisMonth < eMonth)
{
return true;
}
alert("Your credit card has expired or is about to expire");
return false;
}
Finally, the last item: the merchandise selected. You'll need
to make one minor modification to the OPTION elements and give
them values so you can add them up. Then it's simply a matter
of walking the list of options and tallying up the result. While
you're checking for a result in excess of $5,000, you should also
say something if the customer didn't order anything:
function merchandiseOK()
{
var tally = Ø;
var optionCount = document.forms[ Ø ].Merchandise.options.length;
for (var k = Ø; k < optionCount; k++)
{
if (document.forms[ Ø ].Merchandise.options[ k ].selected == true)
{
tally += parseInt(document.forms[ Ø ].Merchandise.options[ k ].value,
1Ø);
if (5ØØØ < tally)
{
alert("Sorry, we cannot handle a transaction in excess of
$5,ØØØ.ØØ");
return false;
}
}
}
if (tally == Ø)
{
alert("Sorry, you don't seem to have ordered anything");
return false;
}
return true;
}
Listing 7.4 shows the entire solution, using JavaScript. There
is no separate figure for the JavaScript solution, because as
far as the screen is concerned, there are no differences.
Listing 7.4: JavaScript solution for form validation
<HTML>
<HEAD>
<TITLE>ComputoRama Order Form</TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!-- hide the code!
function nameOK()
{
if (document.forms[ Ø ].FirstName.value.length == Ø)
{
alert("I need a first name, please");
return false;
}
if (document.forms[ Ø ].LastName.value.length == Ø)
{
alert("I need a last name, please");
return false;
}
return true;
}
function isDigit(c)
{
var test = "" + c;
if (test == "Ø" || test == "1" || test == "2" || test == "3" || test == "4"
|| test == "5" || test == "6" || test == "7" || test == "8" || test == "9")
{
return true;
}
return false;
}
function ageOK()
{
if (document.forms[ Ø ].Age.value.length == Ø)
{
alert("Sorry, you have failed to enter an age");
return false;
}
var c = document.forms[ Ø ].Age.value.substring(Ø, 1);
if (isDigit(c) == false)
{
alert("Sorry, you have failed to enter an appropriate age");
return false;
}
var result = parseInt(document.forms[ Ø ].Age.value, 1Ø);
if (result < 18)
{
alert("Sorry, you have failed to enter an appropriate age");
return false;
}
return true;
}
function isAllDigits(s)
{
var test = "" + s;
for (var k = Ø; k < test.length; k++)
{
var c = test.substring(k, k+1);
if (isDigit(c) == false)
{
return false;
}
}
return true;
}
function addressOK()
{
if (document.forms[ Ø ].StreetAddress.value.length == Ø)
{
alert("We need a street address");
return false;
}
if (document.forms[ Ø ].City.value.length == Ø)
{
alert("We need a city");
return false;
}
if (document.forms[ Ø ].State.value.length != 2)
{
alert("We need a 2-letter state abbreviation");
return false;
}
return true;
}
function zipOK()
{
var zip = document.forms[ Ø ].ZIPCode.value;
if (zip.length == 5)
{
var result = isAllDigits(zip);
if (result == false)
{
alert("Invalid character in zip code");
}
return result;
}
else if (zip.length == 1Ø)
{
var result = isAllDigits(zip.substring(Ø,5));
if (result == true)
{
if (zip.substring(5,6) != "-")
{
result = false;
}
else
{
result = isAllDigits(zip.substring(6,1Ø));
}
}
if (result == false)
{
alert("Invalid character in zip code");
}
return result;
}
else
{
alert("Invalid zip code; please re-enter it");
return false;
}
}
function phoneOK()
{
if (document.forms[ Ø ].Phone1.value.length != 3)
{
alert("We need a phone number, including area code");
return false;
}
if (document.forms[ Ø ].Phone2.value.length != 3)
{
alert("We need a phone number, including area code");
return false;
}
if (document.forms[ Ø ].Phone3.value.length != 4)
{
alert("We need a phone number, including area code");
return false;
}
if (isAllDigits(document.forms[ Ø ].Phone1.value) == false)
{
alert("Bad character in phone number");
return false;
}
if (isAllDigits(document.forms[ Ø ].Phone2.value) == false)
{
alert("Bad character in phone number");
return false;
}
if (isAllDigits(document.forms[ Ø ].Phone3.value) == false)
{
alert("Bad character in phone number");
return false;
}
return true;
}
function doubleForMod1Ø(c)
{
var d = Ø + c;
if (d == Ø) return Ø;
if (d == 1) return 2;
if (d == 2) return 4;
if (d == 3) return 6;
if (d == 4) return 8;
if (d == 5) return 1; // 5+5 = 1Ø; 1+Ø = 1
if (d == 6) return 3; // 6+6 = 12; 1+2 = 3
if (d == 7) return 5; // 7+7 = 14; 1+4 = 5
if (d == 8) return 7; // 8+8 = 16; 1+6 = 7
return 9; // (digit must be 9) 9+9 = 18; 1+8 = 9
}
function sumForMod1Ø(s)
{
var v = parseInt(s, 1Ø); // get the value
var result = doubleForMod1Ø(Math.floor(v / 1ØØØ));
v = v % 1ØØØ;
result += Math.floor(v / 1ØØ);
v = v % 1ØØ;
result += doubleForMod1Ø(Math.floor(v / 1Ø));
v = v % 1Ø;
result += v;
return result;
}
function validateCreditCardNumber()
{
if (document.forms[ Ø ].CreditCardNumber1.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (document.forms[ Ø ].CreditCardNumber2.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (document.forms[ Ø ].CreditCardNumber3.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (document.forms[ Ø ].CreditCardNumber4.value.length != 4)
{
alert("The credit card number is not completely filled out");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber1.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber2.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber3.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (isAllDigits(document.forms[ Ø ].CreditCardNumber4.value) == false)
{
alert("The credit card number contains invalid characters");
return false;
}
if (document.forms[ Ø ].CreditCardType[ 1 ].checked == true) // Visa
{
if (document.forms[ Ø ].CreditCardNumber1.value.substring(Ø,1) != "4")
{
alert("The credit card number is not valid; please re-enter it");
return false;
}
}
else // must be MasterCard
{
var prefix =
parseInt(document.forms[Ø].CreditCardNumber1.value.substring(Ø,2));
if (prefix < 51 || 55 < prefix)
{
alert("The credit card number is not valid; please re-enter it");
return false;
}
}
var sum = sumForMod1Ø(document.forms[ Ø ].CreditCardNumber1.value);
sum += sumForMod1Ø(document.forms[ Ø ].CreditCardNumber2.value);
sum += sumForMod1Ø(document.forms[ Ø ].CreditCardNumber3.value);
sum += sumForMod1Ø(document.forms[ Ø ].CreditCardNumber4.value);
if (sum % 1Ø != Ø)
{
alert("The credit card number is not valid; please re-enter it");
return false;
}
return true;
}
function dateOK()
{
if (document.forms[ Ø ].ExpirationMonth.value.length == Ø)
{
alert("You must fill in the expiration date");
return false;
}
if (isDigit(document.forms[ Ø ].ExpirationMonth.value.substring(Ø,1)) ==
false)
{
alert("Expiration date should be numeric");
return false;
}
var eMonth = parseInt(document.forms[ Ø ].ExpirationMonth.value, 1Ø);
if (eMonth < 1 || 12 < eMonth)
{
alert("Expiration date is out of range");
}
if (document.forms[ Ø ].ExpirationYear.value.length == Ø)
{
alert("You must fill in the expiration date");
return false;
}
if (isDigit(document.forms[ Ø ].ExpirationYear.value.substring(Ø,1)) == false)
{
alert("Expiration date should be numeric");
return false;
}
var eYear = parseInt(document.forms[ Ø ].ExpirationYear.value, 1Ø);
if (eYear < 5Ø)
{
eYear += 2ØØØ;
}
else
{
eYear += 19ØØ;
}
var today = new Date(); // get today's date
var thisYear = 19ØØ + today.getYear();
var thisMonth = 1 + today.getMonth();
if (eYear < thisYear)
{
alert("Your credit card seems to have expired");
return false;
}
if (thisYear < eYear)
{
return true;
}
if (eMonth < thisMonth)
{
alert("Your credit card seems to have expired");
return false;
}
if (thisMonth < eMonth)
{
return true;
}
alert("Your credit card has expired or is about to expire");
return false;
}
function merchandiseOK()
{
var tally = Ø;
var optionCount = document.forms[ Ø ].Merchandise.options.length;
for (var k = Ø; k < optionCount; k++)
{
if (document.forms[ Ø ].Merchandise.options[ k ].selected == true)
{
tally += parseInt(document.forms[ Ø ].Merchandise.options[ k ].value);
if (5ØØØ < tally)
{
alert("Sorry, we cannot handle a transaction in excess of
$5,ØØØ.ØØ");
return false;
}
}
}
if (tally == Ø)
{
alert("Sorry, you don't seem to have ordered anything");
return false;
}
return true;
}
function checkForm()
{
if (nameOK() == false)
{
return;
}
if (ageOK() == false)
{
return;
}
if (addressOK() == false)
{
return;
}
if (zipOK() == false)
{
return;
}
if (phoneOK() == false)
{
return;
}
if (validateCreditCardNumber() == false)
{
return;
}
if (dateOK() == false)
{
return;
}
if (merchandiseOK() == false)
{
return;
}
document.forms[ Ø ].submit();
}
// end of code -->
</SCRIPT>
</HEAD>
<BODY>
<FORM ACTION="mailto:mailhost@computoRama.usa.com" METHOD=POST>
<TABLE BORDER="2" CELLPADDING="1">
<TR>
<TD ROWSPAN="2">Who Are You?</TD>
<TD><INPUT TYPE="text" NAME="FirstName" SIZE=2Ø></TD>
<TD><INPUT TYPE="text" NAME="MiddleInitial" SIZE=1></TD>
<TD><INPUT TYPE="text" NAME="LastName" SIZE=2Ø></TD>
<TD><INPUT TYPE="text" NAME="Age" SIZE=3></TD>
</TR>
<TR>
<TD><FONT SIZE="-2">First Name</FONT></TD>
<TD><FONT SIZE="-2">MI</FONT></TD>
<TD><FONT SIZE="-2">Last Name></TD>
<TD><FONT SIZE="-2">Age</TD>
</TR>
<TR>
<TD ROWSPAN="3">How Do We Contact You?</TD>
<TD COLSPAN="4" VALIGN="TOP">Street Address: <TEXTAREA
name="StreetAddress" rows=2 cols=3Ø></TEXTAREA></TD>
</TR>
<TR>
<TD COLSPAN="2">City: <INPUT TYPE="text" NAME="City"
SIZE=2Ø></TD>
<TD COLSPAN="2">State: <INPUT TYPE="text" NAME="State"
SIZE=2></TD>
</TR>
<TR>
<TD COLSPAN="2">ZIP Code: <INPUT TYPE="text" NAME="ZIPCode"
SIZE=1Ø></TD>
<TD COLSPAN="2">Daytime Phone
(<INPUT TYPE="text" NAME="Phone1" SIZE=3>)
<INPUT TYPE="text" NAME="Phone2" SIZE=3>-
<INPUT TYPE="text" NAME="Phone3" SIZE=4></TD>
</TR>
<TR>
<TD>Credit Card
<INPUT TYPE="radio" NAME="CreditCardType" VALUE="Visa"
CHECKED>Visa
<INPUT TYPE="radio" NAME="CreditCardType"
VALUE="MasterCard">M/C</TD>
<TD COLSPAN="2" ALIGN="CENTER">
<INPUT TYPE="text" NAME="CreditCardNumber1" SIZE=4>
<INPUT TYPE="text" NAME="CreditCardNumber2" SIZE=4>
<INPUT TYPE="text" NAME="CreditCardNumber3" SIZE=4>
<INPUT TYPE="text" NAME="CreditCardNumber4" SIZE=4></TD>
<TD COLSPAN="2">Expiration Date:
<INPUT TYPE="text" NAME="ExpirationMonth" SIZE=2>/
<INPUT TYPE="text" NAME="ExpirationYear" SIZE=2></TD>
</TR>
<TR>
<TD>Merchandise</TD>
<TD COLSPAN=4><SELECT MULTIPLE NAME="Merchandise" SIZE=1>
<OPTION SELECTED VALUE="2ØØØ"> HAL-47Ø <OPTION
VALUE="3ØØØ"> Banana9ØØØ
<OPTION VALUE="8ØØ"> High Res Monitor <OPTION VALUE="5Ø">
Low Res Monitor
<OPTION VALUE="25Ø"> Deluxe Keyboard <OPTION VALUE="4Ø">
Regular Keyboard
<OPTION VALUE="2ØØØ"> Laser Printer <OPTION VALUE="6ØØ">
Inkjet Printer <OPTION VALUE="2ØØ"> Dot Matrix Printer
<OPTION VALUE="1ØØ"> Mouse <OPTION VALUE="125"> Trackball
<OPTION VALUE="5ØØ"> Scanner
</SELECT></TD>
</TR>
<TR>
<TD ALIGN=CENTER COLSPAN="5">
<H1>Thank You For Your Order!</H1>
</TD>
</TR>
</TABLE>
<CENTER>
<INPUT TYPE="button" VALUE="Ship It!" ONCLICK="checkForm()">
<INPUT TYPE="reset" VALUE="Clear Entries">
</CENTER>
</FORM>
</BODY>
</HTML>
You can further improve the JavaScript solution. You could perform
additional checking for post office box addresses (hint: make
a copy of the street address and convert the copy to uppercase),
because only the United States Postal Service can deliver to a
post office box. You could verify that the state is a valid post
office abbreviation (convert it to uppercase). If you're really
ambitious, you can try tying the state, zip code, and area code
together to see if they work (an address in Georgia with a zip
code that starts with 8 and an area code of 919 would be a bad
address, for example). A confirmation box announcing what customers
have purchased and how much they're about to spend would be a
very nice touch. If the customer clicks on CANCEL, no harm done.
While you have the customer there, why not scroll additional advertising
along the status bar?
Although this is a fictitious example, the techniques used here
do carry over to real-world applications. In particular, some
of the functions used in the Java-Script solution-in particular
isDigit() and isAllDigits()-are quite useful for checking numeric
output, such as the phone number and credit card number validation
in this chapter, or driver's license and social security numbers.
The MOD 10 algorithm is in fact used by most major credit cards,
and I've tested it against all of my bank cards-it really works.

Contact
reference@developer.com with questions or comments.
Copyright 1998
EarthWeb Inc., All rights reserved.
PLEASE READ THE ACCEPTABLE USAGE STATEMENT.
Copyright 1998 Macmillan Computer Publishing. All rights reserved.