API
@-Formulas
JavaScript
LotusScript
Reg Exp
Web Design
Notes Client
XPages
 
Generic Form Validation
When you need to validate fields on a form, this is an easy way to accomplish this using Regular Expressions.

There are many web sites outlining how to use Regular Expressions and the syntax and everything, so I won't go into that here. I will describe how to make a generic, reusable, form validator using Regular Expressions.

Step 1

Create three page design elements. One will have the Trim String function, one will have the Get Field Value function, and one will have the function outlined in this document. The page design elements should be named trim.js, getFieldValue.js, and validateForm.js.

Step 2

After creating these design elements, you will need to include 3 external JavaScript functions on your form. This can be done in the HTML Head section of your form with the following formula:

DbName := @ReplaceSubstring(@Subset(@DbName; -1); @Char(92) : " "; "/" : "+");
@NewLine + "<script language=\"JavaScript\" src=\"/" + DbName + "/trim.js\"></script>" + @NewLine + "<script language=\"JavaScript\" src=\"/" + DbName + "/getFieldValue.js\"></script>" + @NewLine + "<script language=\"JavaScript\" src=\"/" + DbName + "/validateForm.js\"></script>" + @NewLine

Note: instead of specifying the full path to the JavaScript pages, you can use a BASE HREF and specify relative URL's to the pages, as outlined here.

Step 3

Next, you will need to populate some global arrays that define how the form should be validated.

There are three arrays that determine the check for required fields (fields that must have a value)
requiredFields = array of the fields that will be required. These are the internal field names.
requiredFieldMessages = array of the messages that will appear if any of the fields in the "requiredFields" array is absent.
requiredMatchingDefaultOK = array of true/false values that check to see if it's ok if the required field matches its default value. For example, you may have field help as a default value for the field. If that's the case, you may want the user to change the value from the default.

NOTE: The array requiredFields is the baseline for the number of entries.
Extra elements in either requiredFieldMessages or requiredMatchingDefaultOK are ignored.
Missing elements in requiredFieldMessages are replaced with a canned "field <fieldname> is required" message.
Missing elements in requiredMatchingDefaultOK are replaced with true (which means it's ok if the field matches the default value).

Step 4

There are five arrays that determine the check for the formatting of the fields (the field value has to be in a certain format or cannot be in a certain format).
formatFields = array of the fields that will be checked for format. These are the internal field names.
formatSuccesses = array of arrays. Each entry can be a single value or an array. The values are the regular expressions that must be met for the checking to proceed.
formatMatchAllSuccesses = array of true/false values. If an entry is true, then all of the corresponding values in the formatSuccesses array must be met for checking to proceed. If an entry is false, then just one of the corresponding values in the formatSuccesses array must be met for checking to proceed. If the corresponding value in formatSuccesses is a single value instead of an array (or an array of one entry), then it doesn't matter if this value is true or false.
In other words, let's say the first element in formatSuccesses is an array of 3 values. If the field value must match all three of these criteria, then put true as the first element in formatMatchAllSuccesses. If it only has to match one of those three (it can be in this format or this format or this format), then put false as the first element in formatMatchAllSuccesses.
formatFailures = array of arrays. Each entry can be a single value or an array. The values are the regular expressions that flag a failure in formatting.
formatMatchAllFailures = array of true/false values. If an entry is true, then all of the corresponding values in the formatFailures array must be met for checking to fail. If an entry is false, then just one of the corresponding values in the formatFailures array must be met for checking to fail. If the corresponding value in formatFailures is a single value instead of an array (or an array of one entry), then it doesn't matter if this value is true or false.
formatMessages = array of strings. Each entry is a string. These are the messages that are shown to the user if either the success entries or the failure entries flag an error.

NOTE: The array formatFields is the baseline for the number of entires.
Extra elements in any of the other "format" arrays are ignored.
Missing elements in formatSuccesses are replaced with ".*" - this would be a regular expression that would match anything.
Missing elements in formatFailures are replaced with "^[\b]" - this would be a regular expression that would attempt to match a backspace at the beginning of the word. In other words, it will be replaced with a regular expression that will never fail.
Missing elements in formatMatchAllSuccesses are replaced with false - this means that only one entry must match to proceed.
Missing elements in formatMatchAllFailures are replaced with false - this means that only one entry must match to fail.
Missing elements in formatMessages are replaced with a canned "field <fieldname> is not formatted correctly" message.

Step 5

To use the functions, during your submit make a call to isFormFormattedCorrectly and pass in a pointer to the form.

The function will return true if all the required fields are present and all the fields are formatted correctly. The function will display an error message to the user and return false if any required field is not present or if a field is not formatted correctly. The user will receive only one error message (the first one found) and not all required/formatting messages.

Example:

<FORM NAME="TestForm" onSubmit="return isFormFormattedCorrectly(document.forms['TestForm']);">

The next couple of pages contain the code for the validateForm.js page you are supposed to create.


var requiredFields = new Array();
var requiredFieldMessages = new Array();
var requiredMatchingDefaultOK = new Array();
var formatFields = new Array();
var formatSuccesses = new Array();
var formatMatchAllSuccesses = new Array();
var formatFailures = new Array();
var formatMatchAllFailures = new Array();
var formatMessages = new Array();

function evenOutArrays() {
   if (requiredFields.length < requiredFieldMessages.length) { requiredFieldMessages.length = requiredFields.length; }
   if (requiredFields.length < requiredMatchingDefaultOK.length) { requiredMatchingDefaultOK.length = requiredFields.length; }
   if (requiredFieldMessages.length < requiredFields.length) {
      var x = requiredFieldMessages.length;
      requiredFieldMessages.length = requiredFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         requiredFieldMessages[i] = "Field " + requiredFields[i] + " is a required field.";
      }
   }
   if (requiredMatchingDefaultOK.length < requiredFields.length) {
      var x = requiredMatchingDefaultOK.length;
      requiredMatchingDefaultOK.length = requiredFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         requiredMatchingDefaultOK[i] = true;
      }
   }
   if (formatFields.length < formatSuccesses.length) { formatSuccesses.length = formatFields.length; }
   if (formatFields.length < formatMatchAllSuccesses.length) { formatMatchAllSuccesses.length = formatFields.length; }
   if (formatFields.length < formatFailures.length) { formatFailures.length = formatFields.length; }
   if (formatFields.length < formatMatchAllFailures.length) { formatMatchAllFailures.length = formatFields.length; }
   if (formatFields.length < formatMessages.length) { formatMessages.length = formatFields.length; }
   if (formatSuccesses.length < formatFields.length) {
      var x = formatSuccesses.length;
      formatSuccesses.length = formatFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         formatSuccesses[i] = ".*";
      }
   }
   if (formatMatchAllSuccesses.length < formatFields.length) {
      var x = formatMatchAllSuccesses.length;
      formatMatchAllSuccesses.length = formatFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         formatMatchAllSuccesses[i] = false;
      }
   }
   if (formatFailures.length < formatFields.length) {
      var x = formatFailures.length;
      formatFailures.length = formatFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         formatFailures[i] = "^[\b]";
      }
   }
   if (formatMatchAllFailures.length < formatFields.length) {
      var x = formatMatchAllFailures.length;
      formatMatchAllFailures.length = formatFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         formatMatchAllFailures[i] = false;
      }
   }
   if (formatMessages.length < formatFields.length) {
      var x = formatMessages.length;
      formatMessages.length = formatFields.length;
      for (var i = x; i < requiredFields.length; i++) {
         formatMessages[i] = "Field " + formatFields[i] + " is not formatted correctly.";
      }
   }
} // Ends the "evenOutArrays" function

function areRequiredFieldsPresent(form) {
   for (var i=0; i < requiredFields.length; i++) {
      eval("var field = form." + requiredFields[i]);
      if (field) {
         // NOTE: THE TRIM JAVASCRIPT FUNCTION MUST BE INCLUDED
         // NOTE: THE GETFIELDVALUE JAVASCRIPT FUNCTION MUST BE INCLUDED
         if (trim(getFieldValue(field)) == "") {
            alert(requiredFieldMessages[i]);
            field.focus();
            return false; // Return as soon as a failure is detected
         } // Ends the check to see if the field value is blank
         if (field.defaultValue) {
            if ( (getFieldValue(field) == field.defaultValue) && ( !requiredMatchingDefaultOK[i]) ) {
               alert(requiredFieldMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
         } // Ends the check to see if the field has a default value
      } // Ends the check to make sure the field exists
   } // Move on to the next field
   return true;
} // Ends the "areRequiredFieldsPresent" function


function areSuccessesPresent(form) {
   for (var i=0; i < formatFields.length; i++) {
      eval("var field = form." + formatFields[i]);
      if (field) { // Make sure the field is found
         // NOTE: THE TRIM JAVASCRIPT FUNCTION MUST BE INCLUDED
         // NOTE: THE GETFIELDVALUE JAVASCRIPT FUNCTION MUST BE INCLUDED
         var value = trim(getFieldValue(field));
         var successes = formatSuccesses[i];
         if (typeof(successes[0]) == "object") { // If it's an array
            // Go through all the expressions and see if they all match and see if any match
            var allMatched = true;
            var anyMatched = false;
            for (var x=0; x < successes.length; x++) {
               var exp = new RegExp(successes[x], "gi");
               var check = exp.test(value);
               if ( !check ) { allMatched = false; }
               if ( check ) { anyMatched = true; }
            }
            // If the developer said they all have to match and they didn't all match, return an error
            if (formatMatchAllSuccesses[i] && !allMatched) {
               alert(formatMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
            // If none of them matched, it doesn't matter what the developer said, return an error
            if ( !anyMatched ) {
               alert(formatMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
         } else { // The formatSuccesses entry is a single value, not an array
            var exp = new RegExp(successes, "gi");
            var check = exp.test(value);
            if ( !check ) { // If that single expression didn't match the criteria (thus, a failure)
               alert(formatMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
         } // Ends the check to see if the format successes entry is an array or a single value
      } // Ends the check to see if the field exists
   } // Move on to the next field
   return true; // If we got this far, everything worked
} // Ends the "areSuccessesPresent" function

function areFailuresPresent(form) {
   for (var i=0; i < formatFields.length; i++) {
      eval("var field = form." + formatFields[i]);
      if (field) { // Make sure the field is found
         // NOTE: THE TRIM JAVASCRIPT FUNCTION MUST BE INCLUDED
         // NOTE: THE GETFIELDVALUE JAVASCRIPT FUNCTION MUST BE INCLUDED
         var value = trim(getFieldValue(field));
         var failures = formatFailures[i];
         if (typeof(failures[0]) == "object") { // If it's an array
            // Go through the expressions and see if any match and see if they all match
            var allMatched = true;
            var anyMatched = false;
            for (var x=0; x < failures.length; x++) {
               var exp = new RegExp(failures[x], "gi");
               var check = exp.test(value);
               if ( !check ) { allMatched = false; }
               if ( check ) { anyMatched = true; }
            }
            // If the developer says they all have to match to cause a failure, then cause a failure
            if (formatMatchAllFailures[i] && allMatched) {
               alert(formatMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
            // If the developer says that any match causes a failure, then cause a failure
            if (!formatMatchAllFailures[i] && anyMatched ) {
               alert(formatMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
         } else { // The formatSuccesses entry is a single value, not an array
            var exp = new RegExp(failures, "gi");
            var check = exp.test(value);
            if ( check ) { // If that single expression matched the criteria (thus, a failure)
               alert(formatMessages[i]);
               field.focus();
               return false; // Return as soon as a failure is detected
            }
         } // Ends the check to see if the format successes entry is an array or a single value
      } // Ends the check to see if the field exists
   } // Move on to the next field
   return true; // If we made it this far, everything passed
} // Ends the "areFailuresPresent" function

function isFormFormattedCorrectly(form) {
   evenOutArrays();
   if ( !(areRequiredFieldsPresent(form)) ) { return false; } // Return as soon as a failure is detected
   if ( !(areSuccessesPresent(form)) ) { return false; }
   if ( !(areFailuresPresent(form)) ) { return false; }
   return true;
} // Ends the "isFormFormattedCorrectly" function