Section 1: Introduction
Data validation can be accomplished through the use of nested if/else statements.
- If the program needs to verify the validity of the input data before calculations are attempted, the structure shown in the pseudocode below can be used.
If (dataItem1 fails test1) Or (dataItem1
fails test2) Then
Notify user
Require that dataItem1 be re-entered
ElseIf (dataItem2 fails test1) Or (dataItem2
fails test2) Then
Notify user
Require that dataItem2 be re-entered
ElseIf (dataItem3 fails test1) Or (dataItem3
fails test2) Then
Notify user
Require that dataItem3 be re-entered
.
.
.
ElseIf (dataItemn fails test1) Or (dataItemn
fails test2) is invalid Then
Notify user
Require that dataItemn be re-entered
Else
Read input data
Perform calculations as specified
End If
Notice that if any invalid data is detected, the calculations are not performed.
- Instead, one of the other else branches is taken, bypassing the else branch that performs the calculations.
Section 2: Incorrect Approach
If the calculations are not placed inside of an else branch, but are instead placed outside of the if/else structure, then the program will detect an error but still attempt to perform the calculations.
- The following pseudocode shows this incorrect approach.
If (dataItem1 is invalid) Then
Notify user
Require that dataItem1 be re-entered
ElseIf (dataItem2 is invalid) Then
Notify user
Require that dataItem2 be re-entered
ElseIf (dataItem3 is invalid) Then
Notify user
Require that dataItem3 be re-entered
.
.
.
ElseIf (dataItemn is invalid) Then
Notify user
Require that dataItemn be re-entered
End If
Read input data
Perform calculations as specified
Section 3: Common Input Errors
When performing data validation, there are several conditions that you should consider to see if they interfere with the normal processing.
Input data may be subject to any of the following conditions:
- no value is entered
- text is entered instead of numeric value
- an incorrect numeric type is entered
- negative value is entered when positive value is expected
- incorrect range of values may be entered
- 0 value is entered
The order in which you test conditions matters.
- For example, if user input fails the numeric test then there is no point in checking to see if it is greater than 0.
Section 4: Sample Input Error Detection
Notice that each of the following functions has a single return statement.
No entry
To check to see if the user forgot to enter a value in a field, check to see if the value property is equal to "" or null.
- If it is, display an error message.
Here is a function that does that:
function somethingEntered(fieldName, label)
{
var returnValue=false;
if ( (document.getElementById(fieldName).value == null) ||
(document.getElementById(fieldName).value.length == 0))
{
alert("You must enter a value in " + label + ".");
returnValue=false;
}
else returnValue=true;
return returnValue;
}
Non numeric
To check to see if the value entered in a field is numeric, use the isNaN function.
- If it is not a number then an error message should be displayed.
Here is a function that does that:
function numberEntered(fieldName, label)
{
var returnValue=false;
if (isNaN(document.getElementById(fieldName).value))
{
alert("You must enter a number in " + label + ".");
returnValue=false;
}
else returnValue=true;
return returnValue;
}
Non-integer entered
To check to see if a value is not an integer, there are various tests, such as the following:
Here is a function that does that:
//-----------------------------------------------------------------------------
// This function returns true if a string contains a number that is an
integer.
// It accepts a number like 35.0 as an integer.
//-----------------------------------------------------------------------------
function isInteger(sNum)
{
return (sNum!="" && !isNaN(sNum) && (sNum/1)==parseInt(sNum));
}
Other approaches can be found here.
Negative value
Check to see if a value is positive, and if it is not then display an error message.
Here is a function that does that:
function positiveNumberEntered(fieldName, label)
{
var returnValue=false;
if (+document.getElementById(fieldName).value < 0)
{
alert("You must enter a positive number in " + label + ".");
returnValue=false;
}
else returnValue=true;
return returnValue;
}
Outside range
Check to see if a value is within a certain range, and if it is not then display an error message.
Here is a function that does that:
function correctRangeEntered(fieldName, label, min, max)
{
var returnValue=false;
if ((+document.getElementById(fieldName).value < min) ||
(+document.getElementById(fieldName).value > max))
{
alert("You must enter a number in " + label + " between " + min +
" and " + max + ".");
returnValue=false;
}
else returnValue=true;
return returnValue;
}
If an invalid value is entered into a text box, display a message box on the screen asking them to provide the required input and return the focus to the unfilled text box using the focus method.
- Code to highlight the invalid entry is included later.
Here is a set of pre-written data validation routines.
Section 5: Highlighting Invalid Entries
In order to allow the user to correct invalid input more easily, return the focus to the control in question, and then highlight the invalid entry in the text box so that they don't have to erase the existing entry before entering the correct value.
Use the focus method to move the focus to a particular control:
document.getElementById(fieldName).focus();
To highlight the invalid text, use the following command:
document.getElementById(fieldName).select();
If you want, you can copy the following function into the <head> tag of your HTML page, and each time that you need to require the user to re-enter data, you can call this function by passing the text box name as a parameter, such as highlightField("txtMPH");.
//---------------------------------------------------------------------------
// This function accepts a text box id as a parameter,
// sets the focus to that box, and highlights the text.
//---------------------------------------------------------------------------
function highlightField(fieldName)
{
document.getElementById(fieldName).focus();
document.getElementById(fieldName).select();
}
Section 6: Example
//------------------------------------------------------------------------
// This version detects errors in a single textbox with a single
statement.
// Therefore the error message is generic.
//------------------------------------------------------------------------
function checkEmail1()
{
var addr;
document.getElementById("lblResult").value= "";
if (
// no input provided
(document.getElementById("txtAddress").value == "")
// number entered instead of address
|| (!isNaN(document.getElementById("txtAddress").value))
// too few characters
|| (document.getElementById("txtAddress").value.length < 7)
// missing '@'
|| (document.getElementById("txtAddress").value.indexOf("@") < 0)
// missing '.'
|| (document.getElementById("txtAddress").value.indexOf(".") < 0)
// '@' and '.' too close together
|| (document.getElementById("txtAddress").value.lastIndexOf(".")
-
document.getElementById("txtAddress").value.lastIndexOf("@")
<= 1)
// final '.' too close to the end
|| (document.getElementById("txtAddress").value.lastIndexOf(".")
>
document.getElementById("txtAddress").value.length - 3) )
{
alert("Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
// This else branch, and thus the input and processing statements
within, will
// only be executed if no invalid input was detected.
else
{
addr = document.getElementById("txtAddress").value;
document.getElementById("lblResult").value = addr + " may be a
valid e-mail address.";
}
}
//------------------------------------------------------------------------
// This version detects errors in a single textbox with multiple
checks.
// Therefore the error messages can be more informative.
//------------------------------------------------------------------------
function checkEmail2()
{
var addr;
document.getElementById("lblResult").value= "";
if (document.getElementById("txtAddress").value == "")
{
alert("You failed to enter an email address. " +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
else if (!isNaN(document.getElementById("txtAddress").value))
{
alert("You entered a number instead of an address. " +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
else if (document.getElementById("txtAddress").value.length < 7)
{
alert("There don't seem to be an adequate number of characters.
" +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
else if (document.getElementById("txtAddress").value.indexOf("@") <
0)
{
alert("Your entry does not have an '@'. " +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
else if (document.getElementById("txtAddress").value.indexOf(".") <
0)
{
alert("Your entry does not have a '.'. " +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
else if
(document.getElementById("txtAddress").value.lastIndexOf(".") -
document.getElementById("txtAddress").value.lastIndexOf("@") <=
1)
{
alert("Your '@' and '.' are too close together. " +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
else if
(document.getElementById("txtAddress").value.lastIndexOf(".") >
document.getElementById("txtAddress").value.length - 3)
{
alert("Your last '.' seems too close to the end. " +
"Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
// This else branch, and thus the input and processing statements
within, will only be
// executed if no invalid input was detected.
else
{
addr = document.getElementById("txtAddress").value;
document.getElementById("lblResult").value = addr + " may be a
valid e-mail address.";
}
}
//------------------------------------------------------------------------
// This version is just sick and wrong. The input and processing are
// outside of the If/Then/Else statement. That means that it will
detect
// the error okay, but then STILL tries to process the invalid input!
//------------------------------------------------------------------------
function checkEmail3()
{
var addr;
document.getElementById("lblResult").value= "";
alert("This is the WRONG way to do it! The input and processing are
outside " +
"of the if/else statement.")
alert("It will detect the error okay, but then STILL tries to
process " +
" the invalid input! Watch....");
if ((document.getElementById("txtAddress").value == "")
|| (!isNaN(document.getElementById("txtAddress").value))
|| (document.getElementById("txtAddress").value.length < 7)
|| (document.getElementById("txtAddress").value.indexOf("@") <
0)
|| (document.getElementById("txtAddress").value.indexOf(".") <
0)
|| (document.getElementById("txtAddress").value.lastIndexOf(".")
-
document.getElementById("txtAddress").value.lastIndexOf("@")
<= 1)
|| (document.getElementById("txtAddress").value.lastIndexOf(".")
<
document.getElementById("txtAddress").value.length - 3) )
{
alert("Please enter an email address in the format " +
"username@domain.ext, where domain is domain " +
"name and ext is the extension like com or edu.");
highlightField("txtAddress");
}
// These should have been placed inside an else branch.
// Because they were not, they will be executed even if invalid
input is provided.
addr = document.getElementById("txtAddress").value;
document.getElementById("lblResult").value = addr + " may be a
valid e-mail address.";
}
//---------------------------------------------------------------------------
// This function accepts a text box id as a parameter,
// sets the focus to that box, and highlights the text.
//---------------------------------------------------------------------------
function highlightField(fieldName)
{
document.getElementById(fieldName).focus();
document.getElementById(fieldName).select();
}
Link to email checker code
Link to another data validation example
Section 7: Errors in Calculations
One of the basic problems to look for when writing error checking routines is conditions that can adversely affect mathematical calculations.
- Among the most obvious conditions are a divide by zero and a logarithm of 0 (Math.log(0)).
- Neither of these conditions are valid.
- The first step is to look closely at the calculations to see if any of them offer the potential for either condition.
If problems in the calculation are encountered, look closely at the calculations to see if there is an alternative approach.
Example
Given the loan amount, percent interest per year, loan duration in years, and payments per year, a mortgage calculator calculates the size of the payment for each loan period as well as the total interest paid over the life of the loan.
The formulas used appear below:
Variable Name | Formula |
---|---|
totalPayments | loanDuration multiplied by paymentsPerYear |
decIntPerYear | percentInterest divided by 100 |
decIntPerPayment | decIntPerYear divided by paymentsPerYear |
factor |
1 - (1 + decIntPerPayment)-totalPayments decIntPerPayment |
paySize | loanAmount divided by factor |
totalInt | (paySize * paymentsPerYear * loanDuration) - loanAmount |
The formula for calculating factor is a potential trouble spot because of the division.
- We must be sure that the divisor, decIntPerPayment, cannot equal 0.
- What conditions could make decIntPerPayment equal 0? The answer is a 0% interest rate.
- If you borrow from a family member, a 0% interest rate may be possible.
-
How do we avoid a divide by zero then?
- If decIntPerPayment is not equal to zero, we calculate factor as specified.
-
If decIntPerPayment is equal to zero, then we cannot use the formula that was provided to
calculate factor.
- Instead, we must set factor equal to totalPayments in order for the subsequent calculations to work correctly.
- Problems like that above can be ascertained by looking closely at the calculations.
The next formula that could potentially be subject to a divide by zero problem is the paySize formula.
-
The divisor in this case is factor.
- We must test the value of factor to be sure it is not equal to zero before calculating paySize.
-
If factor is equal to 0, it is not apparent how to react.
- One approach may be to simply set the paySize equal to the loanAmount, since we are unable to calculate a valid result.