Forms in JavaScript
References
Forms in Javascript
In the CGI (Common Gateway Interface) model, which is how an HTML form's data are normally submitted to the Web server, a form with its input data is submitted to the web as a package. The form's input data are processed by a program or a page on the Web server, as specified in the form's action attribute.
With JavaScript, you can perform local verification (meaning: in the browser) of the form's data.
What this really means is that you can use JavaScript to make sure that the form data are correct even before it gets sent to the Web server.
Let's look at some basic information regarding how HTML forms and form elements are handled by JavaScript.
The Form Object
The JavaScript Form object represents an HTML form. Forms are always found as elements of the forms[ ] array, which is a property of the document object. Forms appear in the forms[ ] array in the order in which they appear within the document. So, document.forms[0] refers to the first form in a document.
One of the most interesting properties of the Form object is the elements[ ] array, which contains JavaScript objects (of various types) that represent the various input elements in the HTML form. Elements appear in the elements[ ] array in the same order as they appear in the document. So, document.forms[0].elements[2] refers to the third element of the first form in the document of the current window.
The JavaScript Form object has two methods, submit( ) and reset( ), that serve the same purpose as a Submit or a Reset button, respectively. If you use the submit( ) method, the form is submitted just as if the user had clicked on a Submit button. And if you use the reset( ) method, the form is reset just as if the user had clicked on a Reset button.
Most importantly for our purposes, the Form object also has an onsubmit event handler to detect the submission of the form. There is also an onreset event handler that detects a form reset, of course.
The onsubmit handler is called by JavaScript just before the form is submitted to the server.
Now here is one of the most important features with regard to doing form validation: You can cancel the form's submission by returning false to the onsubmit event handler. This feature means that you can check the user's input for errors and avoid submitting the form with incomplete or invalid data to a server page or program, by returning false. We'll see how this works in our sample, a bit later.
Form Elements
As I said in the previous section, every Form object has an elements[ ] property, which is an array of the JavaScript objects that represent the input elements contained in the form.
Below is a table of the possible HTML form elements and their corresponding JavaScript objects.
Every form element object has a type property that identifies what type of element it is. The third column in the following table gives the value of this property for each object. The elements[ ] array of the form object contains various types of form element objects; the type property allows you to loop through the elements[ ] array and operate on the form objects it contains in ways that depend on their type.
Every Form element object also has a form property. This property is simply a reference to the Form object that contains the element! This property provides a useful way for a form element object to refer to another form element from its event handler.
| HTML Tag | Corresponding JavaScript Object | type Property's Value | Description and Event Handler(s) Available |
|---|---|---|---|
| <input type="button"> | Button | "button" | A push button; onclick |
| <input type="checkbox"> | Checkbox | "checkbox" | A toggle button without radio button behavior; onclick |
| <input type="file"> | FileUpload | "file" | An input field for entering the name of a file to upload to the web server; onchange |
| <input type="hidden"> | Hidden | "hidden" | Data submitted with the form but not visible to the user; no event handlers. |
| <option> | Option | none | A single item within a Select object; event handlers are on the Select object, not on individual Option objects. |
| <input type="password"> | Password | "password" | An input field for password entry - - typed characters are not visible; onchange |
| <input type="radio"> | Radio | "radio" | A toggle button with radio behavior - - only one can be selected at a time; onclick |
| <input type="reset"> | Reset | "reset" | A push button that resets a form; onclick |
| <select> | Select | "select-one" | A list or drop-down menu from which one item may be selected; onchange |
| <select multiple="multiple"> | Select | "select-multiple" | A list or drop-down menu from which multiple items may be selected; onchange |
| <input type="submit"> | Submit | "submit" | A push button that submits a form; onclick |
| <input type="text"> | Text | "text" | A single-line text entry field; onchange |
| <textarea> | Textarea | "textarea" | A multi-line text entry field; onchange |
Within a form element event handler, the this keyword refers to the element object itself. This fact means that this.form always refers to the form that contains the element. So, an event handler of a form element can refer to a sibling object (element) in the same form with an expression like this:
this.form.elements[4]
Naming Forms and Form Elements
Every HTML form element has a name attribute that must be set in the tag if the element's datum (value) is to be submitted to a Web server program or page. But this name attribute is useful for JavaScript coding, too.
The <form> tag itself also has a name attribute that you can set. This attribute has nothing to do with form submission. It exists for the convenience of JavaScript programmers. If the name attribute is defined in a <form> tag, when the form object is created for that form, it is stored as usual as an element in the forms[ ] array of the document object; but it is also stored in its own personal property of the document object. The name of this newly defined property is, of course, the value of the name attribute.
So, if you define a form with HTML like this:
<form name="questionnaire">
...
</form>
you can refer to that form in JavaScript (in most browsers) as:
document.questionnaire
Now, as I mentioned just above, each HTML form element has a name attribute. This attribute's value is used by JavaScript to automatically create a new property of the form object that refers to each element. The name of this property is, of course, the value of the name attribute in each element. So, for instance, you can refer to an element named "question1" in a form named "questionnaire" like this (in most browsers):
document.questionnaire.question1
Using IDs
All of the major browsers now support the document.getElementById( ) method, so this method is now the preferred way of getting a reference to the elements in your HTML pages, using JavaScript. What this means for you is that you will normally want to put both a name attribute and an id attribute in your form elements. Give the name attribute and the id attribute the same value.
The name attribute will still be used as the element's variable name in the action page or program, on the Web server, .
The id attribute will be used to get a reference to the element, using the document.getElementById( ) method that I just mentioned, so you can get the element's value, or change a property, or do some other useful operation on the element.
You have already seen several examples of how to use document.getElementById( ) in some of the sample code in previous handouts. But for good measure, here is another look at one of the previous examples:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Samples.css">
<title>Conditional Expression</title>
<script type="text/javascript">
/* <![CDATA[ */
function checkTheNumber()
{
var yourNumber = document.getElementById("yourNumber").value;
var result;
(yourNumber > 100) ? result = "greater than" : result = "less than or equal to";
document.getElementById("compareText").innerHTML = result;
document.getElementById("numberStuff").style.visibility = "visible";
}
/* ]]> */
</script>
</head>
<body>
<div id="mainDiv">
<div id="numberStuff" style="visibility:hidden;">
Your number is <span id="compareText"></span> 100.
</div>
<br>
<form action="" method="post">
<input type="text" id="yourNumber" name="yourNumber">
<br>
<br>
<input type="button" value="Test the number" onclick="checkTheNumber()">
</form>
</div>
</body>
</html>
You can see the above code running again, here....
Please note these points about the above code:
-
The document.getElementById() method is being used in several places.
- In the first place, it is being used to get the string value that the user typed into the text input field.
- In the second place, it is being used to display the string in the variable called "result", by replacing the HTML contents of the <span> tag.
- In the third place, it is being used to change the value of the CSS style property called "visibility". You will see many more examples of how you can change CSS style properties in a few more weeks.
- The property of the <span> element which is being used to display the value of the result variable, is innerHTML. My choice of this property is important, since Firefox does not recognize the other possible choice, which is innerText. I suggest that you *not* use the innerText property.
The this Keyword
The this keyword in JavaScript is designed to refer to the object which refers to the HTML tag which this is in.
For example, in the section "Simple Form Validation" below, you will see a form tag like this:
<form
name="myForm"
id="myForm"
method="get"
action="ThankYou.html"
onsubmit = "return validateForm(this);">
Please notice this in the call to function validateForm(this), which is in the onsubmit event handler attribute. In this context, meaning in the <form> tag, this refers to the Form object which refers to this <form> tag.
In the validateForm() function definition in that same page, which is
function validateForm(f)please note the f which is defined as the function's parameter. This f receives the value of this when the function is called.
Please recall that each of the HTML form elements in the page has a name attribute, which becomes a property of the form object, of the same name. This situation very handily gives us the ability to refer to an element's object as in this statement (which comes from the same function that we just looked at):
f.textstuff.value
where textstuff is the name attribute's value in the first input tag of that form. As you will see below in the section "Form Element Values" in this handout, the value property allows you to get the text that the user has typed into this input field.
You will see a lot of statements in the rest of this handout's examples, which use this kind of syntax.
Radio Buttons (and Checkboxes)
Radio buttons and checkboxes in an HTML form can have the same name attribute (in "sets" of these buttons). This is because the browser requires that radio button elements within a set (or group) in an HTML form all be given the same name.
(Checkboxes are not required to have identical name attributes, but they may, at the discretion of the HTML developer.)
For example, if you have some radio buttons on your form that allow the user to indicate their favorite web browser, all of the radio buttons in this set must have the same name; for example, "favoriteBrowser".
But when more than one element in a form has the same name attribute (as in the situation with radio buttons) JavaScript puts those elements into an array that is named by this same name. So, if the radio buttons that we just mentioned are part of our form named "questionnaire", you could refer to them like this:
document.questionnaire.favoriteBrowser[0] (for the first one)
document.questionnaire.favoriteBrowser[1] (for the second one)
etc.
Form Element Values
In addition to its name property, almost every JavaScript Form element has a value property. When a form is submitted, the user's input data are passed to the web server in the form of name/value pairs. The name and value properties for each element provide the information that the browser uses to construct these pairs of data.
The value property is read/write. The initial value of the value property, of course, is usually specified by the value attribute of the HTML tag that defines the form element, as in a text input field.
The value for TextArea objects is simply the text contained between the opening and closing <textarea>...</textarea> tags.
The value for Button, Reset, and Submit objects is the text that is displayed by the push button. Depending on the platform, changing this value may or may not change what is displayed on the button. Also, the value of a Button or Reset object is never submitted with the form. The value of a Submit object is submitted only when the Submit object was the one that the user clicked to submit the form.
The value for Checkbox and Radio objects is the string value that is submitted with the form if the Checkbox or Radio object is checked. (The checked property indicates the state of the object.) You should note carefully that each and every checkbox or radio object (element) is represented in the elements[ ] array, even if the user has not checked all of them. You need to loop through the checkbox or radio elements and test for the checked property's being true, to find out which element(s) the user has checked.
For a Select object, there is no value property. The value property belongs, in this case, to the Option objects. It is this value that is submitted with the form, and that indicates which option was selected.
The Option object is different also in that it is not technically a form element. The Option objects are contained by the Select object. This means that the Select object is the only form element that contains other objects. They are contained in its options[ ] array.
Below is some code that shows how you can use the value property to see what a form element/control contains:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Samples.css">
<title>Form Example</title>
<script type="text/javascript">
/* <![CDATA[ */
function showFormInfo()
{
var formInfoString = "";
var theElement;
formInfoString += "Your name is " + document.getElementById("yourName").value + ".";
formInfoString += "\nYour favorite color is ";
/* This is the old way of referring to the radio buttons. Note that
the old way uses the "name" attribute of both the form tag and the
input tag to refer to the objects. This old way only works in
certain browsers, including IE:
for (var i = 0; i < document.myForm.FavColor.length; i++)
{
if (document.myForm.FavColor[i].checked == true)
{
formInfoString += document.myForm.FavColor[i].value;
break;
}
}
*/
/* This is the cross-browser way of referring to the objects, using the
"id" attribute of the form tag, and checking the "type" and "name" of
the element objects: */
for (var i = 0; i < document.getElementById("myForm").elements.length; i++)
{
theElement = document.getElementById("myForm").elements[i];
if ((theElement.type == "radio") && (theElement.name == "FavColor"))
{
if (theElement.checked == true)
{
formInfoString += theElement.value;
break;
}
}
}
formInfoString += ".";
formInfoString += "\ni is " + i;
alert(formInfoString);
}
/* ]]> */
</script>
</head>
<body>
<div id="mainDiv">
<form
method="post"
action=""
name="myForm"
id="myForm"
onsubmit="showFormInfo(); return false;">
Please type your name:<br>
<input
type="text"
name="yourName" id="yourName">
<br/>
<br/>
Please select your favorite color:<br>
<input type="radio" name="FavColor" value="red">Red<br>
<input type="radio" name="FavColor" value="orange">Orange<br>
<input type="radio" name="FavColor" value="yellow">Yellow<br>
<input type="radio" name="FavColor" value="green">Green<br>
<input type="radio" name="FavColor" value="blue">Blue<br>
<input type="radio" name="FavColor" value="violet">Violet<br>
<br>
<br>
<input type="submit" value="Send the info">
</form>
</div>
</body>
</html>
You can see the above code running here.
Please note these points about the above code:
- The value property of the element object contains the element's value and may be assigned or displayed.
- The checked property of radio button objects (as shown here) and checkbox objects (very similar to the code shown here) can be tested to see which elements are checked.
- However, if you were testing for checked elements in a set of checkbox objects, you would not put in the break statement that I have included in this code. The break statement causes the for loop to stop looping, since we expect only one radio button to be checked. But with checkboxes, more than one can be checked, and we would want to loop through all of the checkbox objects in the set.
- The onsubmit event handler is in the form tag.
- You can stop a form's submission to the server by returning false to the onsubmit event handler.
Simple Form Validation
You can validate the user's form input with JavaScript. If the data are acceptable, the form submission can proceed normally. But if you find some missing or unacceptable information in the form, you can cancel the form submission. You have the final say about whether or not the form's data are submitted to the Web server. I assure you, such power exists! :-)
You can cancel a form's submission by returning false to the onsubmit event handler.
Here is some code that shows a simple, form-specific (not general, that is) way of validating the form data:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Samples.css">
<title>Simple Form Validation</title>
<script type="text/javascript">
/* <![CDATA[ */
function simpleValidateForm(f)
{
var returnValue = true;
if (f.textstuff.value == "")
{
alert("Please type something in the text input box.");
returnValue = false;
}
if (f.Comments.value == "")
{
alert("Please type something in the Comments text area.");
returnValue = false;
}
var colorSelected = false;
for (var i = 0; i < f.FavoriteColor.length; i++)
{
if (f.FavoriteColor[i].checked)
{
colorSelected = true;
}
}
if (colorSelected == false)
{
alert("Please select your favorite color.");
returnValue = false;
}
var petSelected = false;
for (var i = 0; i < f.Pets.length; i++)
{
if (document.myForm.Pets[i].checked)
{
petSelected = true;
}
}
if (!petSelected)
{
alert("Please tell us what pets you have.");
returnValue = false;
}
return returnValue;
}
/* ]]> */
</script>
</head>
<body>
<div id="mainDiv">
<form
name="myForm"
id="myForm"
method="get"
action="ThankYou.html"
onsubmit = "return simpleValidateForm(this);">
<table border="0" cellpadding="10" cellspacing="0">
<tr>
<td align="right">Type some text here:</td>
<td><input
type="text"
name="textstuff"
size="40"
maxlength="40"></td>
</tr>
<tr>
<td align="right" valign="top">Type some Comments here:</td>
<td><textarea name="Comments" cols="30" rows="4"></textarea></td>
</tr>
<tr>
<td align="right" valign="top">Please tell us your favorite color:</td>
<td><input type="radio"
name="FavoriteColor"
value="blue">Blue
<br>
<input type="radio"
name="FavoriteColor"
value="red">Red
<br>
<input type="radio"
name="FavoriteColor"
value="green">Green</td>
</tr>
<tr>
<td align="right" valign="top">Please tell us what pets you have:</td>
<td>
<input type="checkbox"
name="Pets"
value="dog">Dog
<br>
<input type="checkbox"
name="Pets"
value="cat">Cat
<br>
<input type="checkbox"
name="Pets"
value="fish">Fish
<br>
<input type="checkbox"
name="Pets"
value="none">None of the above
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Submit the Form Data"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
You can see the above code running here.
Please note these points about the above code:
- Radio button sets, and checkbox sets which have the same name attribute in each checkbox in the set, are represented by an Array object in JavaScript. Thus, you can use a for() loop to inspect each item in the set.
- The this keyword in the onsubmit code refers to the object that it is in, which in this case is the form object itself.
- In the custom function simpleValidateForm( ), the parameter f receives the reference to the form object that is passed in as the this keyword (see the previous note). So the parameter f in this function is a reference to the form object.
- The line of code
if (f.textstuff.value == "")
is exactly equivalent to usingif (document.myForm.textstuff.value == "")
or evenif (document.getElementById("myForm").textstuff.value == "")since the parameter f, as noted above, contains a reference to the form object. - The line of code that tests for a checked "favorite color" radio button,
if (f.FavoriteColor[i].checked)
is using another JavaScript shortcut. This line is exactly equivalent to the lineif (f.FavoriteColor[i].checked == true)
- In the code that tests for false in the variable petSelected,
another
JavaScript shortcut is used. The statement
if (!petSelected)
does exactly the same job as the statementif (petSelected == false)
since the exclamation point in JavaScript is the NOT logical operator. Logically, not true is the same as false.
JavaScript Include Files
We briefly discussed using JavaScript Include Files in the first handout. In that handout, I referred to them as JavaScript Source Files. You can use either term; they are pretty much equivalent.
The concept of JavaScript Include Files is to put some JavaScript code into a separate (text) file and then to include the JavaScript code in your HTML document at the place where the JavaScript code is needed. If you choose to use JavaScript Include Files in this way, you should note these points:
- The include/source file is saved with a .js file extension.
- The include/source file can contain only JavaScript code. No HTML code is allowed, which means that the <script>... </script> tags are also not allowed.
- You include the source file into your HTML document with code
like this:
<script type="text/javascript" src="mySource.js"></script> - You are not limited to only one JavaScript Include File in your HTML page. You can include as many source files as you need, as long as you use a separate set of <script>...</script> tags for each include/source file that you include.
- If you also have JavaScript code typed directly into your HTML document, you must use another set of <script>...</script> tags to enclose the code that is in the HTML page.
- You can include the JavaScript include/source file into as many separate HTML documents as you want. This is, in fact, one of the advantages of using include/source files. You can include code from one file into many HTML files, so there is only one place to change the JavaScript code if it needs to be changed.
Generic Form Validation
The prior section "Simple Form Validation" in this handout shows how to validate form data on a form- and element-specific basis. Now here is some code that shows a generic, reusable approach to validating form data with JavaScript.
Also, please note that this generic validation code is in a JavaScript Include File, the concept of which was presented in the previous section of the handout.
The code below is an example of using a JavaScript include file to validate form data. It can be seen running here.
The HTML page, with the <form>...</form> tag and the JavaScript include/source <script></script> tag in it, is formVerification3.html:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Samples.css">
<title>Form Verification Example</title>
<style type="text/css">
body { font-family: Arial, sans-serif; }
td { padding-right: 20px; padding-top: 7px; vertical-align: top; }
.col1 { text-align: right; }
</style>
<script type="text/javascript" src="formValidation.js"></script>
</head>
<body>
<div id="mainDiv">
<!--
Here is a sample form to test our verification function. Note that we
call verify() from the onsubmit() event handler, and return whatever
value it returns. Also note that we use the onsubmit() handler as
an opportunity to set properties on the form objects that verify()
will use in the verification process.
-->
<form novalidate onsubmit="this.firstname.required = true;
this.firstname.labelname = 'First Name';
this.lastname.required = true;
this.lastname.labelname = 'Last Name';
this.state.required = true;
this.state.labelname = 'State';
this.zipcode.required = true;
this.zipcode.zipcodefield = true;
this.zipcode.labelname = 'Zip Code';
this.email.required = true;
this.email.emailfield = true;
this.email.labelname = 'E-mail Address';
this.pwd.required = true;
this.pwd.passwordfield = true;
this.pwd.passwordStrength = 'strong';
this.pwd.labelname = 'Password';
this.phonenumber.required = true;
this.phonenumber.phonenumberfield = true;
this.phonenumber.labelname = 'Phone Number';
this.numberOfChildren.required = true;
this.numberOfChildren.numeric = true;
this.numberOfChildren.labelname = 'Number of Children';
this.numberOfChildren.min = 0;
this.rateThisExample.required = true;
this.rateThisExample.min = 1;
this.rateThisExample.max = 10;
this.rateThisExample.labelname = 'Rate this Example';
return verify(this);" method="get" action="ThankYou.html"
enctype="multipart/form-data">
<table border="0">
<tr>
<td class="col1">
First name: *
</td>
<td>
<input type="text" name="firstname">
</td>
</tr>
<tr>
<td class="col1">
Last name: *
</td>
<td>
<input type="text" name="lastname">
</td>
</tr>
<tr>
<td class="col1">
E-mail Address: *
</td>
<td>
<input type="text" name="email">
</td>
</tr>
<tr>
<td class="col1">
Password: *
</td>
<td>
<input type="password" name="pwd">
</td>
</tr>
<tr>
<td class="col1">
Phone Number: *
</td>
<td>
<input type="text" name="phonenumber">
</td>
</tr>
<tr>
<td class="col1">
State: *
</td>
<td>
<select name="state">
<option value="">-- Select a State --</option>
<option value="AK">Alaska</option>
<option value="AR">Arkansas</option>
<option value="NC">North Carolina</option>
<option value="TX">Texas</option>
<option value="VA">Virginia</option>
</select>
</td>
</tr>
<tr>
<td class="col1">
Zip Code: *
</td>
<td>
<input type="text" name="zipcode">
</td>
</tr>
<tr>
<td class="col1">
Comments:
</td>
<td>
<textarea cols="40" rows="2" name="comments"></textarea>
</td>
</tr>
<tr>
<td class="col1">
Number of children: (enter the number 0 if none) *
</td>
<td valign="top">
<input type="text" name="numberOfChildren">
</td>
</tr>
<tr>
<td class="col1">
Rate this example on a scale of 1 to 10: *
</td>
<td valign="top">
<input type="text" name="rateThisExample">
</td>
</tr>
<tr>
<td class="col1">
Your Gender: *
</td>
<td>
<input type="radio" name="Your_Gender" value="Male" title="required">
Male
<br/>
<input type="radio" name="Your_Gender" value="Female">
Female
</td>
</tr>
<tr>
<td class="col1">
Pets you Like: *
</td>
<td valign="top">
<input type="checkbox" name="Pets_you_Like" value="Dogs" title="required">
Dogs
<br/>
<input type="checkbox" name="Pets_you_Like" value="Cats">
Cats
<br/>
<input type="checkbox" name="Pets_you_Like" value="Birds">
Birds
<br/>
<input type="checkbox" name="Pets_you_Like" value="Fish">
Fish
<br/>
<input type="checkbox" name="Pets_you_Like" value="None">
None of the above
<br/>
</td>
</tr>
<tr>
<td class="col1">
(* = Required field)
</td>
<td>
</td>
</tr>
<tr>
<td class="col1">
<input type="submit" value="Submit">
</td>
<td>
<input type="reset" value="Clear form">
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
Here is the code in the include/source file, formValidation.js:
// formValidation.js
//
// New Version -- Oct 2013
//
// You may freely use this script for all educational, commercial, or
// non-commercial purposes. Your use of this script is at your own
// risk. No warranty or guarantee is expressed or implied.
//Here is a utility function that returns true if a string contains only
//whitespace characters:
function isblank(s)
{
for (var I = 0; I < s.length; I++)
{
var c = s.charAt(I);
if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
}
return true;
}
//This function validates an e-mail address for some simple requirements:
//1 or more non-numeric characters followed by zero or more characters
//(including underscores), followed by "@", followed by 1 or more
//characters followed by zero or more characters (including underscores),
//followed by ".", followed by 1 or more characters.
function validateEmail(emailaddress)
{
var retValue = true;
var mailRE = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
retValue = mailRE.test(emailaddress);
return retValue;
}
//This function validates a phone number
function validatePhoneNumber(phonenum)
{
var retValue = true;
var phoneRE = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/;
retValue = phoneRE.test(phonenum);
return retValue;
}
//This function validates a Zip code
function validateZipcode(zipcode)
{
var retValue = true;
var zipRE = /^\d{5}-?(\d{4})?$/;
retValue = zipRE.test(zipcode);
return retValue;
}
//This function validates a password for strength
function validatePassword(pwd, strength)
{
var retValue;
var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
var mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g");
var enoughRegex = new RegExp("(?=.{6,}).*", "g");
if ((strongRegex.test(pwd)) && ((strength == "strong") || (strength == "medium") ||
(strength == "weak")))
{
retValue = true;
}
else if ((mediumRegex.test(pwd)) && ((strength == "medium") || (strength == "weak")))
{
retValue = true;
}
else if ((enoughRegex.test(pwd)) && (strength == "weak"))
{
retValue = true;
}
else
{
retValue = false;
}
return retValue;
}
//Here is the function that performs the form verification. It will be invoked
//from the onSubmit() event handler. The handler should return whatever value
//this function returns.
function verify(f)
{
var msg;
var empty_fields = "";
var errors = "";
var empty_count = 0;
var number_count = 0;
var e;
var o;
var is_empty;
var nameStuff;
//Loop through the elements of the form, looking for all
//text, textarea, select, password, and file elements that have a required="true"
//property defined.
//
//NOTE: text, textarea, file, password, and select elements must define the "required"
//property in the onsubmit attribute of the <form> tag.
//
//Also look for all radio button and checkbox elements that have a
//title="required" property defined.
//
//NOTE: Radio and checkbox elements
//must define a title="required" attribute in the first input tag of each set.
//The radio and checkbox elements that are required must include the
//title="required" attribute in ONLY ONE (the first) of the elements in the set.
//
//NOTE: You can also add a property "labelname" to non-radio and non-checkbox
//fields to use the "labelname" value in the error messages instead of the
//field's "name" attribute value. You can also include underscores (_) in
//the field's "name" attribute. The underscores will be replaced with
//spaces in the error messages, as the field's name.
//
//NOTE: For radio and checkbox fields, you can include underscores (_) in
//the field's "name" attribute. The underscores will be replaced with
//spaces in the error messages, as the field's name.
//
//Check for fields that are empty and make a list of them. Use this list of
//empty fields to report the required empty fields to the user.
//
//If any of these elements have a "min", "max", or "numeric" property defined,
//then verify that they are numbers and that they are in the right range.
//
//If any fields have an "emailfield" property defined, verify for an
//e-mail address pattern.
//
//If any fields have a "phonenumberfield" property defined, verify for a
//phone number pattern.
//
//If any fields have a "zipcodefield" property defined, verify for a
//Zip code pattern.
//
//If any fields have a "passwordfield" property defined, verify for a
//password of the required strength. If you use the "passwordfield"
//property, you can also use a "passwordStrength" property. It defaults
//to strong. The possible explicit values are weak, medium, and strong.
//
//Put together error messages for fields that are wrong.
for (var i = 0; i < f.elements.length; i++)
{
e = f.elements[i];
if ((e.type == "text") || (e.type == "textarea") || (e.type == "file") || (e.type == "password"))
{
//Check if the field is empty
if ((e.value == null) || (e.value == "") || isblank(e.value))
{
is_empty = true;
if (e.required == true)
{
if (e.labelname != null)
{
empty_fields += "\n " + e.labelname;
}
else
{
nameStuff = e.name.replace(/_/g," ");
empty_fields += "\n " + nameStuff;
}
empty_count++;
continue;
}
}
else
{
is_empty = false;
}
//Now check for fields that are supposed to be numeric.
if (!is_empty && ((e.numeric == true) || (!isNaN(parseInt(e.min))) || (!isNaN(parseInt(e.max)))))
{
var v = parseFloat(e.value);
if (isNaN(v) ||
((!isNaN(parseInt(e.min))) && (v < parseInt(e.min))) ||
((!isNaN(parseInt(e.max))) && (v > parseInt(e.max))))
{
if (e.labelname != null)
{
errors += " - " + e.labelname + " must be a number";
}
else
{
errors += " - " + e.name.replace(/_/g," ") + " must be a number";
}
if (!isNaN(parseInt(e.min)))
errors += " that is greater than or equal to " + e.min;
if ((!isNaN(parseInt(e.max))) && (!isNaN(parseInt(e.min))))
errors += " and less than or equal to " + e.max;
else if (!isNaN(parseInt(e.max)))
errors += " that is less than " + e.max;
errors += ".\n";
number_count++;
}
}
//Now do a simple pattern test for e-mail addresses:
if (!is_empty && e.emailfield == true)
{
var validEmail = validateEmail(e.value);
if (!validEmail)
{
if (e.labelname != null)
{
errors += " - " + e.labelname + " must be a valid e-mail address.";
}
else
{
errors += " - " + e.name.replace(/_/g," ") + " must be a valid e-mail address.";
}
errors += "\n";
}
}
//Now do a simple pattern test for phone number:
if (!is_empty && e.phonenumberfield == true)
{
var validPhone = validatePhoneNumber(e.value);
if (!validPhone)
{
if (e.labelname != null)
{
errors += " - " + e.labelname + " must be a valid phone number.";
}
else
{
errors += " - " + e.name.replace(/_/g," ") + " must be a valid phone number.";
}
errors += "\n";
}
}
//Now do a simple pattern test for Zip code:
if (!is_empty && e.zipcodefield == true)
{
var validZip = validateZipcode(e.value);
if (!validZip)
{
if (e.labelname != null)
{
errors += " - " + e.labelname + " must be a valid Zip code.";
}
else
{
errors += " - " + e.name.replace(/_/g," ") + " must be a valid Zip code.";
}
errors += "\n";
}
}
//Now do a pattern test for password strength:
if (!is_empty && ((e.type == "password") && (e.passwordfield == true)))
{
var strengthIndicator = "";
if ((e.passwordStrength) && (e.passwordStrength != null) && ((e.passwordStrength == "strong") ||
(e.passwordStrength == "medium") || (e.passwordStrength == "weak")))
{
strengthIndicator = e.passwordStrength;
}
else
{
strengthIndicator = "strong"; // default to strong
}
var validPassword = validatePassword(e.value, strengthIndicator);
if (!validPassword)
{
if (e.labelname != null)
{
errors += " - " + e.labelname + " must be a valid " + strengthIndicator + " password";
}
else
{
errors += " - " + e.name.replace(/_/g," ") + " must be a valid " + strengthIndicator + " password";
}
switch (e.passwordStrength)
{
case "strong":
errors += ", with at least 8 characters including upper- and lower-case letters, at least 1 numeric digit, and at least 1 special character."
break;
case "medium":
errors += ", with at least 7 characters including upper- and lower-case letters, and at least 1 numeric digit."
break;
case "weak":
errors += ", with at least 6 characters."
break;
default:
errors += "."
}
errors += "\n";
}
}
}
if (((e.type == "select-one") || (e.type == "select-multiple")) && (e.required == true))
{
var itemSelected = false;
for (var j = 0; j < e.options.length; j++)
{
o = e.options[j];
if (o.value != "")
{
if (o.selected == true)
{
itemSelected = true;
}
}
}
if (itemSelected == false)
{
if (e.labelname != null)
{
empty_fields += "\n " + e.labelname;
}
else
{
nameStuff = e.name.replace(/_/g," ");
nameStuff = nameStuff.replace("[","");
nameStuff = nameStuff.replace("]","");
empty_fields += "\n " + nameStuff;
}
empty_count++;
}
}
if (((e.type == "radio") || (e.type == "checkbox")) && (e.title == "required"))
{
var itemChecked = false;
var inputObjLength = f[e.name].length;
if (typeof(inputObjLength) == "undefined")
{ // There is only 1 radio button, and thus no array
if (e.checked)
{
itemChecked = true;
}
}
else
{ // There are multiple radio buttons, which are in an array
for (var itemNum = 0; itemNum < f[e.name].length; itemNum++)
{
if (f[e.name][itemNum].checked == true)
{
itemChecked = true;
break;
}
}
}
if (itemChecked == false)
{
if (e.labelname != null)
{
empty_fields += "\n " + e.labelname;
}
else
{
nameStuff = e.name.replace(/_/g," ");
nameStuff = nameStuff.replace("[","");
nameStuff = nameStuff.replace("]","");
empty_fields += "\n " + nameStuff;
}
empty_count++;
}
}
}
//Now, if there were any errors, display the messages, and
//return false to prevent the form from being submitted.
//Otherwise, return true.
if ((empty_fields == "") && (errors == ""))
{
return true;
}
msg = "_____________________________________________________________________\n\n";
if (empty_count + number_count == 1)
{
msg += "The form was not submitted because of the following error.\n";
msg += "Please correct this error and re-submit.\n";
}
else
{
msg += "The form was not submitted because of the following errors.\n";
msg += "Please correct these errors and re-submit.\n";
}
msg += "_____________________________________________________________________\n\n";
if (empty_fields != "")
{
if (empty_count == 1)
{
msg += " - The following required field is empty or not selected: " + empty_fields + "\n";
}
else
{
msg += " - The following required fields are empty or not selected: " + empty_fields + "\n";
}
if (errors != "") msg += "\n";
}
msg += errors; //It doesn't matter if errors is empty or not, just add it
alert(msg);
return false;
}
The above code can be seen running here.
Please note these points about the above code:
-
The attribute
novalidate
in the <form> tag prevents browsers such as Google Chrome from doing their own built-in validation in response to the required properties in the form fields. - The code in the <script>...</script> tag in the <head> section, meaning the code in the JavaScript include/source file, is generic and reusable. You can copy formValidation.js and create your own file of that name, then include it into any form page and use it just as it is.
- The form-specific code is in the <form> tag, in the onsubmit event handler.
- In the HTML form's onsubmit attribute, the JavaScript keyword this refers to the form object itself.
- Also in the HTML form's onsubmit attribute code, we are creating
properties of the form's element objects by simply naming them and giving them
values, like this:
this.firstname.required = true;
which creates a required property for the firstname element. This looks strange, but it is a standard and way cool feature of JavaScript. - For radio and checkbox elements, however, the required
property will not work in some browsers such as FireFox.
The title property can be used. Here is how you use the title
property for radio and checkbox elements:
- Put a "title" attribute in the first <input> tag of each set of radio buttons or checkboxes.
- Use "required" as the value of this title attribute.
-
This attribute will look like this:
title="required"
- The HTML form's onsubmit attribute also has code that creates the min, max, and numeric properties for the zip element.
- The method attribute in the <form> tag is "get". This value is used in this sample because the school's Web server does not allow file uploads. In the real world, this value would be "post", which would allow file uploads from the "portrait" file input field.
- In the real world (see the above point), in order to do a file upload, you need to have the enctype="multipart/form-data" attribute in the form tag, also.
- In the custom function verify( ), in the JavaScript code up there in the head
section of the page, the for loop tests for
i < f.elements.length
which you may need a reminder about. Recall, please, that the length property of the form.elements object returns the number of elements in the form. - Also in the verify( ) function, the code
e = f.elements[i];
assigns to the variable e a value that is a reference to the element object for the particular element that we are dealing with for each iteration through the elements array. - Also in the verify( ) function, we check the type property of each element. We only want to deal with text, textarea, select, radio, and checkbox elements.
- The isblank( ) function is a custom function that checks for characters that are not blank, carriage returns, or tabs. If the function finds anything that is a normal (non-whitespace) character, it returns false to indicate that there is something other than whitespace in the string.
- The statement
continue;
causes the current iteration of the for loop to be cut short, and the next iteration to begin. This means that none of the rest of the code in the for loop following continue gets run but the for loop continues with the next iteration. - The code that makes some numeric tests begins with this statement:
if (e.numeric || (e.min != null) || (e.max != null))
which includes some tests for some properties not being null. If the property is null, it means that the property was not created in the onsubmit code in the <form> tag. If the property is not null, it means that the property was created in the onsubmit code in the <form> tag. The code will test the specific values of these properties in just a few more statements, but for now we just need to know if they were created or not. - The parseFloat( ) built-in method returns a number (more specifically, a floating-point number) if it finds a number at the beginning of the string that is its argument (in the parentheses). parseFloat( ) stops processing/finding the number if and when it encounters a non-numeric character in the string. And if parseFloat( ) finds a non-numeric character at the beginning of the string, and/or there is no number in the string, it returns the built-in keyword value NaN, which JavaScript interprets as "not a number".
- You cannot directly test for NaN in JavaScript. You must use the built-in method isNaN( ), which returns true if the value it is testing is the internal, special keyword value NaN.
- As the verify( ) function progresses, it is building two strings that will be used at the end to give information to the user. The string empty_fields will tell the user what required fields have nothing in them, and the string errors will tell the user about other errors such as the value exceeding a max property, etc.
- In the code that tests for the element types "select-one" and "select-multiple" (which are the two kinds of select lists), the for loop's condition tests for e.options.length. You should recall that the elements in a select object are in an array called options, and that the number of items in an array is returned by the length property of an array. The required property of the select element can be set in the onsubmit code because it is a single element that contains other elements: the <option> tags that go in the list.
- The situation for the element types "radio" and "checkbox" is a bit weirder. Each <input> tag that has the type property of "radio" or "checkbox" in the form itself becomes part of an array that has the name of the radio or checkbox elements, as expected. But because each of the elements in a set is a separate <input> tag, and not contained in another, single tag like the <option> tags are contained in the <select> tag (see above), the "required" property cannot be set in the onsubmit code, and must instead be set as an attribute of the <input> tag. And in fact, some browsers such as FireFox will not even create a "required" property for radio or checkbox elements. But we can use a title attribute instead. And since we only want to loop through the array of radio or checkbox elements once per set, we need to set the title attribute only once per set. So make sure that you set the title attribute in the first input tag of a set of radio or checkbox <input> elements.
- Also, still talking about the element types "radio" and "checkbox",
the array for these elements must be
referenced as an associative array in the form object, meaning
that the index of the array
is the name of the set of input elements. So the statement
if (f[e.name][itemNum].checked)
for instance, is referring to the array named e.name (which is a string with a value of the name attribute of the <input> element) -- and remember that the variable/parameter f refers to the form object. So the line of code shown here refers to the [itemNum] element in the e.name array of form f. - In function verify( ), this code
if (!empty_fields && !errors) return true;
returns true to the calling code (in the onsubmit event handler in the <form> tag) if both strings are empty strings. This is some more JavaScript shortcut code. You can test for an empty string by testing for "not string", which in JavaScript is the exclamation point (!) followed by the name of the variable that contains the string. - The return value of true from the verify( ) function is then returned to the onsubmit event handler in the browser, allowing the form submission to occur normally.
- But function verify( ) returns false if there were any errors. This return value of false is then returned to the onsubmit event handler in the browser, causing the form submission to be cancelled.
The submit( ) method
The form object has several methods. One of these is the submit( ) method. This method allows you to cause the form data to be submitted from code, just as if the user had clicked a submit button.
But be aware that the onsubmit event does not occur when you use the submit( ) method. This difference means that you will need to do any validation before you call the submit( ) method.
Here is some code that shows how you could use the submit( ) method to submit the form's data from a hypertext link instead of from a submit button:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Samples.css">
<title>submit() Example</title>
<script type="text/javascript">
/* <![CDATA[ */
function verifySubmit()
{
if (document.getElementById("textstuff").value != "")
{
document.getElementById("theForm").submit();
}
else
{
alert("Please type some text into the input field.");
}
}
/* ]]> */
</script>
</head>
<body>
<div id="mainDiv">
<form
id="theForm"
method="post"
action="https://www.jimlink.net/PHPStuff/testFormData.php">
Type some text here:<br/>
<input
type="text"
name="textstuff"
id="textstuff"
size="40"
maxlength="40"
value="">
<br/>
<br/>
</form>
<a href="#" onclick="verifySubmit(); return false;">Send the Text</a>
</div>
</body>
</html>
You can see the above code running here.
Please note these points about the above code:
- The form does not have an onsubmit event handler.
- The form data will be submitted to the Web server only if the user has typed something into the text field.
- The form data are submitted to the Web server with the submit() method.
- This page will pass the W3C's XHTML validation. The two comment lines that are at the beginning and the end of the <script>...</script> tag will "hide" the JavaScript code from the validator.
- These comment lines contain standard XML code to "mark" the contained code
as "character data" which is not actually validated, but rather ignored by
the validator:
/* <![CDATA[ */
and/* ]]> */
The reset( ) method
The form object also had a reset( ) method. This method allows you to cause the form's input fields to be reset just as if the user had clicked a reset button.
This method is different from the submit( ) method in that if you use the reset( ) method, the onreset event handler is called. Because of this situation, it is possible to get your code into an infinite loop by calling reset( ) in the onreset event handler. Be careful!
Here is some code that shows how you could use the reset( ) method to reset a form's data from a custom reset button:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="Samples.css">
<title>Use the reset( ) Method</title>
<script type="text/javascript">
/* <![CDATA[ */
function verifyReset(f)
{
var resetIt = confirm("Do you really want to clear the form?\n\nClick 'OK' if you want to clear the form.\n\nClick 'Cancel' if you do not want to clear the form.");
if (resetIt)
{
document.getElementById("theForm").reset();
}
else
{
alert("Whew! Your information is still in the form!");
}
}
/* ]]> */
</script>
</head>
<body>
<div id="mainDiv">
<form
id="theForm"
name="myForm"
method="post"
action="https://www.jimlink.net/PHPStuff/testFormData.php">
Type some text here:<br/>
<input
type="text"
name="textstuff"
size="40"
maxlength="40"
value="">
<br/>
<br/>
<a href="#" onclick="verifyReset(); return false;"><img src="images/ResetButton.jpg"
width="160" height="30" alt="Clear the Form" border="0"></a>
<br/>
<br/>
<input type="submit" value="Send the Text">
</form>
</div>
</body>
</html>
You can see the above code running here.
Please note these points about the above code:
- This code uses the reset( ) method in the onclick event handler in the <a> tag that is around the "Clear the Form" image. This code turns the image into a custom reset button.
- This code does not use the reset( ) method in the onreset event handler. If it did, and it returned true, the reset event would occur again and again and again...
[ Optional Section ]
Multi-Page Form
It is possible to send data from one form to another, using Javascript. This means that your forms can be, in effect, multi-part forms.
To make this kind of code work, in the sending form you must do this:
- Use a method in the <form> tag of "get".
- Make sure all of your form elements have a name attribute.
Then, in the receiving form, you must do this:
- Use the location.search property of the document object to obtain the name/value pairs of information from the sending form. (This property returns the query portion of the current URL, including the leading question mark.)
- Put some named elements in the second form (in the second page, which is the action page for the first form), which will receive the values that your code will retrieve from the sending form. These elements can be either visible or hidden.
Here is some sample code for the sending form (this is file TestForm.html):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Test sending form data to another form</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
</head>
<body>
<form method="get" action="secondForm.html">
<table border="0">
<tr>
<td>First name:</td>
<td><input type="text" name="firstname" /></td>
</tr>
<tr>
<td>Last name:</td>
<td><input type="text" name="lastname" /></td>
</tr>
<tr>
<td>E-mail address:</td>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Next >>" /></td>
</tr>
</table>
</form>
</body>
</html>
Here is the sample code for the receiving form: (this is file secondForm.html)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Test getting form data from another form</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<script type="text/javascript">
/* <![CDATA[ */
function getArgs()
{
var args = new Object();
var query = location.search.substring(1);
var pairs= query.split("&");
for (var i = 0; i < pairs.length; i++)
{
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0,pos);
var value = pairs[i].substring(pos+1);
args[argname] = unescape(value);
}
return args;
}
function putArgsInForm()
{
var ourArgs = getArgs();
var f = document.getElementById("ourForm");
if (ourArgs.firstname) f.firstname.value = ourArgs.firstname;
if (ourArgs.lastname) f.lastname.value = ourArgs.lastname;
if (ourArgs.email) f.email.value = ourArgs.email;
}
/* ]]> */
</script>
</head>
<body onload="putArgsInForm()">
<form method="get"
action="thirdForm.html"
name="ourForm" id="ourForm">
<table border="0">
<tr>
<td>Address 1:</td>
<td><input type="text" name="address1" /></td>
</tr>
<tr>
<td>Address 2:</td>
<td><input type="text" name="address2" /></td>
</tr>
<tr>
<td>City:</td>
<td><input type="text" name="city" /></td>
</tr>
<tr>
<td>State:</td>
<td><input type="text" name="state" /></td>
</tr>
<tr>
<td>Zip:</td>
<td><input type="text" name="zip" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Next >>" /></td>
</tr>
<tr>
<td colspan="2">Oh, and just in case you're curious, here are the data from
the first form: (You would not normally display it here.)</td>
</tr>
<tr>
<td>First name:</td>
<td><input type="text" name="firstname" /></td>
</tr>
<tr>
<td>Last name:</td>
<td><input type="text" name="lastname" /></td>
</tr>
<tr>
<td>e-mail address:</td>
<td><input type="text" name="email" /></td>
</tr>
</table>
</form>
</body>
</html>
And now here is the code for the third page, which is also a receiving page: (this is file thirdForm.html)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Test getting form data from another form</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<script type="text/javascript">
/* <![CDATA[ */
function getArgs()
{
var args = new Object();
var query = location.search.substring(1);
var pairs= query.split("&");
for (var i = 0; i < pairs.length; i++)
{
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0,pos);
var value = pairs[i].substring(pos+1);
args[argname] = unescape(value);
}
return args;
}
function putArgsInForm()
{
var ourArgs = getArgs();
var f = document.getElementById("ourForm");
if (ourArgs.firstname) f.firstname.value = ourArgs.firstname;
if (ourArgs.lastname) f.lastname.value = ourArgs.lastname;
if (ourArgs.email) f.email.value = ourArgs.email;
if (ourArgs.address1) f.address1.value = ourArgs.address1;
if (ourArgs.address2) f.address2.value = ourArgs.address2;
if (ourArgs.city) f.city.value = ourArgs.city;
if (ourArgs.state) f.state.value = ourArgs.state;
if (ourArgs.zip) f.zip.value = ourArgs.zip;
}
/* ]]> */
</script>
</head>
<body onload="putArgsInForm()">
<h3>Here are all of the data combined:</h3>
<form method="get"
action=""
name="ourForm" id="ourForm">
<table border="0">
<tr>
<td>First name:</td>
<td><input type="text" name="firstname" /></td>
</tr>
<tr>
<td>Last name:</td>
<td><input type="text" name="lastname" /></td>
</tr>
<tr>
<td>e-mail address:</td>
<td><input type="text" name="email" /></td>
</tr>
<tr>
<td>Address 1:</td>
<td><input type="text" name="address1" /></td>
</tr>
<tr>
<td>Address 2:</td>
<td><input type="text" name="address2" /></td>
</tr>
<tr>
<td>City:</td>
<td><input type="text" name="city" /></td>
</tr>
<tr>
<td>State:</td>
<td><input type="text" name="state" /></td>
</tr>
<tr>
<td>Zip:</td>
<td><input type="text" name="zip" /></td>
</tr>
</table>
</form>
</body>
</html>
You can see the above code running here.
Please note these points about the above code:
- The file secondForm.html calls custom function putArgsInForm( ) in the onload event handler in the <body> tag.
- Custom function putArgsInForm( ) calls custom function getArgs( ) to retrieve the name/value pairs of information from the first form.
- Function getArgs( ) does these things to get at each name/value pair:
- It uses the substring( ) built-in method to get the portion of the URL string that is just past the question mark. The argument sent to the substring( ) method tells substring( ) to return everything in the string starting at position 1, which, in a zero-based language, is the second character, so we skip the beginning question mark.
- It uses the split( ) built-in method to create an array of the name/value pairs. The split( ) method splits a string into pieces at the given delimiter (in this code, the ampersand - &) and puts the pieces into an array of smaller strings.
- It then uses a for loop to iterate through the name/value pairs in the array, getting the name and value strings based on the location of the equal sign that is in each name/value pair string.
- In assigning the value to the args array, it makes use of JavaScript associative arrays, which use strings instead of numbers as the index to the array elements.
- It then returns the args array to the caller.
- The variable ourArgs receives this returned array.
- The appropriate elements in the form are assigned the values from this associative array (ourArgs).
- The code that looks like this:
if (ourArgs.firstname)
is testing for the existence of a property of the array ourArgs. This kind of test is possible because the elements of an associative array can also be referenced as properties of the array. - The code in the third file does similar processing to combine the input from the first and second pages into a single list of your information.
[ Optional Section ]
Another Multi-Page Form
Now here is some code that I found on the WebMonkey resource site. This code does a similar job to that of the preceding section, but in a more generic fashion. The first file is my own form: (this first file is TestWebMonkeyParse.html)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Test Form for Web Monkey URL Parse Test</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> </head> <body> <form action="WebMonkeyParse.html" method="get"> <table border="0"> <tr> <td> First name: </td> <td> <input type="text" name="firstname" /> </td> </tr> <tr> <td> Last name: </td> <td> <input type="text" name="lastname" /> </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="Test it" /> </td> </tr> </table> </form> </body> </html>
Now here is the code that is the action page in the above code, with my added fields at the bottom for displaying the received information: (this next file is WebMonkeyParse.html)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Test Web Monkey's URL parser</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<script type="text/javascript">
/* <![CDATA[ */
<!--
/*
Webmonkey GET Parsing Module
Language: JavaScript 1.0
The parsing of GET queries is fundamental
to the basic functionality of HTTP/1.0.
This module parses GET with JavaScript 1.0.
Source: Webmonkey Code Library
(http://www.hotwired.com/webmonkey/javascript/code_library/)
Author: Patrick Corcoran
Author Email: patrick@taylor.org
*/
function createRequestObject() {
FORM_DATA = new Object();
// The Object ("Array") where our data will be stored.
separator = ',';
// The token used to separate data from multi-select inputs
query = '' + this.location;
// Get the current URL so we can parse out the data.
// Adding a null-string '' forces an implicit type cast
// from property to string, for NS2 compatibility.
query = query.substring((query.indexOf('?')) + 1);
// Keep everything after the question mark '?'.
if (query.length < 1) { return false; } // Perhaps we got some bad data?
keypairs = new Object();
numKP = 1;
// Local vars used to store and keep track of name/value pairs
// as we parse them back into a usable form.
while (query.indexOf('&') > -1) {
keypairs[numKP] = query.substring(0,query.indexOf('&'));
query = query.substring((query.indexOf('&')) + 1);
numKP++;
// Split the query string at each '&', storing the left-hand side
// of the split in a new keypairs[] holder, and chopping the query
// so that it gets the value of the right-hand string.
}
keypairs[numKP] = query;
// Store what's left in the query string as the final keypairs[] data.
for (i in keypairs) {
keyName = keypairs[i].substring(0,keypairs[i].indexOf('='));
// Left of '=' is name.
keyValue = keypairs[i].substring((keypairs[i].indexOf('=')) + 1);
// Right of '=' is value.
while (keyValue.indexOf('+') > -1) {
keyValue = keyValue.substring(0,keyValue.indexOf('+')) + ' ' + keyValue.substring(keyValue.indexOf('+') + 1);
// Replace each '+' in data string with a space.
}
keyValue = unescape(keyValue);
// Unescape non-alphanumerics
if (FORM_DATA[keyName]) {
FORM_DATA[keyName] = FORM_DATA[keyName] + separator + keyValue;
// Object already exists, it is probably a multi-select input,
// and we need to generate a separator-delimited string
// by appending to what we already have stored.
} else {
FORM_DATA[keyName] = keyValue;
// Normal case: name gets value.
}
}
return FORM_DATA;
}
FORM_DATA = createRequestObject();
// This is the array/object containing the GET data.
// Retrieve information with 'FORM_DATA [ key ] = value'.
function loadFields()
{
document.receiver.recvfirstname.value = FORM_DATA["firstname"];
document.receiver.recvlastname.value = FORM_DATA["lastname"];
}
// -->
/* ]]> */
</script>
</head>
<body onload="loadFields();">
<form name="receiver" method="get" action="">
<table border="0">
<tr>
<td> Received first name:
</td>
<td>
<input type="text" name="recvfirstname" />
</td>
</tr>
<tr>
<td> Received last name:
</td>
<td>
<input type="text" name="recvlastname" />
</td>
</tr>
</table>
</form>
</body>
</html>
And now you can see the WebMonkey code in action here.
[ Optional Section ]
E-mailing Form Data
You can cause a form's data to be e-mailed if the computer that is running the browser has a mail client (program) configured. This type of e-mailing is a local (client) process. Another type of e-mail process, which we are not discussing here, is CGI e-mail or e-mail sent by another server-side process such as ColdFusion, PHP, or asp.net.
Please note: Over 50% of e-mail users have a Web-based e-mail service, so this local (client-based) method of sending e-mail is useless for over 50% of your site's users. You might want to seriously consider using a server-side e-mail process or even CGIEMAIL. Most Internet Service Providers (ISPs) have CGIEMAIL installed on their servers. CGIEMAIL is covered in the Web Design II course that we teach in this department. And we teach PHP in this department, also.
Here is some code that shows how local e-mailing can be done:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Form Example</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
</head>
<body>
<div align="left">
<form
method="post"
action="mailto:JLink@dcccd.edu?subject=grand opening sale"
enctype="text/plain">
<table border="0" cellpadding="10" cellspacing="0">
<tr>
<td align="right">Type some text here:</td>
<td><input
type="text"
name="textstuff"
size="40"
maxlength="40"
value="some text to go into the box" /></td>
</tr>
<tr>
<td align="right">Type some text here:</td>
<td><textarea name="Comments" cols="30" rows="4">Some text goes here.</textarea></td>
</tr>
<tr>
<td align="right">Please tell us your favorite color:</td>
<td><input type="radio"
name="FavoriteColor"
value="blue"
checked="checked" />Blue
<br/>
<input type="radio"
name="FavoriteColor"
value="red" />Red
<br/>
<input type="radio"
name="FavoriteColor"
value="green" />Green</td>
</tr>
<tr>
<td align="right">Please tell us what pets you have:</td>
<td>
<input type="checkbox"
name="Pets"
value="dog"
checked="checked" />Dog
<br/>
<input type="checkbox"
name="Pets"
value="cat" />Cat
<br/>
<input type="checkbox"
name="Pets"
value="fish"
checked="checked" />Fish
</td>
</tr>
<tr>
<td align="right">Tell us what TV programs you like to watch (you may select
multiple programs by holding down the Ctrl key while you make
your selections):</td>
<td>
<select name="TV"
multiple="multiple"
size="5">
<option>Gilligan's Island</option>
<option>Mission: Impossible</option>
<option>Star Trek</option>
<option selected="selected">Monday Night Football</option>
<option selected="selected">NCAA March Madness</option>
</select>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Submit" /></td>
</tr>
</table>
</form>
</div>
</body>
</html>
Please note these points about the above code:
- The action attribute of the <form> tag starts with mailto:
- The <form> tag also has an additional attribute, enctype, which must
be just like this to cause the form's data to be sent in text format:
enctype="text/plain"
- If you are using Internet Explorer 6 under the Windows XP operating system,
it is possible that the e-mail message generated by IE and sent to the e-mail
client (program) will not have any content or a subject. This failure is a known
issue by Microsoft. Microsoft's Knowledge Base suggests the following resolution:
ISSUE:
This issue may occur if the following registry key exists, but the required sub keys do not exist:
HKEY_CURRENT_USER\Software\Clients\Mail
The preceding key may be created if you click Yes when you receive the following message when you run MSN Explorer for the first time:
Would you like to get on the Internet and write e-mail through the Start Menu using MSN Explorer?
When you click Yes, the registry key is created, but the additional sub keys are not created.
RESOLUTION:
WARNING: If you use Registry Editor incorrectly, you may cause serious problems that may require you to reinstall your operating system. Microsoft cannot guarantee that you can solve problems that result from using Registry Editor incorrectly. Use Registry Editor at your own risk.
To resolve this issue, use Registry Editor to manually remove the following registry key:
HKEY_CURRENT_USER\Software\Clients\Mail
You can see the above code running here.