The Cold Fusion Web Database Construction Kit

Previous chapterNext chapterContents


- 19 -
Additional Form Data Validation Techniques



Steven D. Drucker

In the previous chapter, you learned about using Cold Fusion to ensure that users enter required information into forms and to validate that information is being properly formatted. As you develop more complex applications, however, you will discover that CF's built-in validation functions can be limiting. This chapter details additional methods for verifying data input and when to use them.

Researching Data Validation Techniques

Two methods for performing data validation are server-side and client-side validation. You should already be familiar with server-side validation if you used the techniques described in Chapter 18, "Form Data Validation." With this technique, the user submits data fields for validation and processing to a program running on the web server. This method is browser-independent, so you can count on the same validation process taking place regardless of what version of vendor's browser you are using. However, this robustness comes at a price. Forms failing server validation need to be resubmitted, increasing the number of requests your server must handle (see Figure 19.1).

Client-side validation involves using a scripting language supported by the user's browser to validate form data before it is sent to the server for processing. Scripting languages are embedded within HTML documents and interpreted by the browser at runtime. Two of these have risen to prominence-- JavaScript (championed by Netscape) and VB Script (supported by Microsoft). Sloughing off field validation onto the client is attractive because it frees up your web server to handle more tasks. Both JavaScript and VB Script, however, are immature technologies and not all browsers support them, so results may vary. If designing for an intranet, where you have some level of control over what browser software is used, client-side scripting can be a powerful addition to your site. If programming for the internet, be aware that JavaScript or VB Script may not run as expected on all platforms and may be completely ignored by some browsers (see Figure 19.2).

Figure 19.1  Using Cold Fusion to validate data entry is an example of a server-side process.

Figure 19.2  Client-side scripting can take a load off your Web server, but be sure to test using multiple browsers.

Validating Data Using JavaScript

JavaScript is a powerful, object-based scripting language developed by Netscape Communications Corporation. At first glance, JavaScript functions resemble C, but don't panic! JavaScript's high-level functionality, similar to Apple's Hypertalk and the XBASE languages, makes it much easier to learn and program.

JavaScript is not JAVA. The JAVA language has received more media hype than perhaps any other language in the history of the world. Netscape, in a shrewd marketing maneuver, capitalized on this hype (and confused the rest of us) by naming their browser scripting language JavaScript. While there are some small similarities between the languages, they remain separate and distinct. Perhaps the biggest difference between the two is that JAVA programs are compiled into applets, whereas JavaScript is coded inline with HTML and interpreted by the browser at runtime.

JavaScript is implemented in Netscape Navigator 2.0+ and ORACLE PowerBrowser. A compatible version, JSCRIPT, was developed by Microsoft Corporation and is supported by Microsoft Internet Explorer 3.0. How these two, slightly different, implementations evolved from the same base specification is a matter of corporate intrigue and well beyond the scope of this book. Rest assured that all examples presented in this chapter were tested and found to be compatible with either browser. Whereas Netscape and Microsoft have announced plans to license their JavaScript interpreter technology to other software developers, you will find that JavaScript implementation and behavior varies between platforms, browsers, and in some cases, different versions of the same browser.


CAUTION: If you rely solely on JavaScript for data validation, be prepared to rigorously test your forms using several different browsers. Support for this language varies greatly.

JavaScript is an evolving language. New features are planned from Netscape. The adoption of these additional features by other browser vendors (Microsoft, Oracle, Spyglass), is uncertain, therefore "TEST, TEST, TEST" when implementing JavaScript functions.

Implementing JavaScript in HTML Forms

JavaScript code can be incorporated into your HTML documents as a combination of statements and functions within a <SCRIPT> tag and as extensions to HTML tags as targets of event handlers.


The <SCRIPT> Tag. JavaScript functions are enclosed within the <SCRIPT> tag. You may enclose as much JavaScript as you like between these tags. In addition, you may place blocks of <SCRIPT> anywhere within your HTML document, although they are customarily placed at the top of the HTML file within the <HEAD>..</HEAD> tags. This is to avoid an error resulting from the user clicking a button to call a JavaScript function (declared farther down the page) which, due to a slow page load, has not yet loaded into the browser.

JavaScript statements are interpreted and executed as they are loaded into the browser. JavaScript functions, however, are not executed until they are called by an event handler on the page. In Listing 19.1, an alert message is displayed as soon as the first window.alert statement is encountered by the browser. The second window.alert message, because it is part of a function, does not appear until after you click a button, calling function notifyme.


CAUTION: JavaScript is a case sensitive language, so be careful when typing in these code listings.

Listing 19.1  JS1.CFM--Large Blocks of JavaScript Statements and Functions Are Usually Contained Within the <HEAD> Tags of Your HTML Documents

<HTML>
<HEAD>
<TITLE>My First JavaScript!</TITLE>
<SCRIPT LANGUAGE="JavaScript">
window.alert("Welcome to the wonderful world of JavaScript!")
function notifyme(msg2user){
     window.alert(msg2user)
     return true
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR=#C0C0C0>
<H3>JavaScript, JavaScript, JavaScript
<HR WIDTH="100%">
</H3>
<BR>
<CENTER>
<FORM NAME="form1">
<INPUT TYPE="button" NAME="sample" VALUE="Click here if you want to never pay ¬taxes again"
             Onclick="notifyme(While JavaScript can perform some miracles, ¬tax relief is not one of them.')">
</FORM>
</BODY>
</HTML>

Hiding JavaScript from Non-supporting Browsers. As previously mentioned, JavaScript is not supported by all browsers. In order to prevent JavaScript source code from being displayed in a browser (see Figure 19.3), you must use a combination of HTML comment tags (<!-- ) and JavaScript comment tags (// for single line, /* */ for multi-line) within the <SCRIPT> tags. The following code snippet demonstrates this technique.

<SCRIPT LANGUAGE="JavaScript">
<!-- //hide this code from old browsers (start)
window.alert("Welcome to the wonderful world of JavaScript!")
/*
     The following function is invoked as an onclick event
*/
function notifyme(msg2user){
     window.alert(msg2user)
     return true
}
//  hide this code from old browsers (end) -->
</SCRIPT>

Figure 19.3 Comments can prevent JavaScript source code from being displayed by older browsers.

JavaScript Events. JavaScript is largely an event driven language. Any time you move or click your mouse, select a block of text, or type data into a form, your browser registers the event. You can create JavaScript event handlers, functions that are triggered as the result of such events. For example, the action of a user changing data in a text field can trigger a routine to validate the data in that field. Similarly, moving the mouse cursor over different parts of a client-side image map can result in additional user instructions to display in the browser's status line. Events to which you may link your own custom procedures are listed in Table 19.1.

Table 19.1  JavaScript Events Are Used to Trigger Calls to Functions

Event Handler Applies to Activates when
onBlur All form objects User's cursor moves away from object
onClick All form objects User clicks except text/object textarea, Links
onChange Text, Text Area, User edits data in object, then focuses changes to Select another object
onFocus All form objects User's cursor moves onto object
onLoad Document page HTML object completes loading
onMouseOver Links User places mouse cursor over object
onSelect Text, Textarea User selects text within object
onSubmit Form Form is submitted for processing
onUnload Page User exits the current HTML page

JavaScript Event Handlers. Most of the JavaScript validation functions you create will execute as event handlers. The general format for linking a form object to an event is:

<[FormObject] EventHandler="JavaScript Code">

In the following code snippet, two input text boxes are defined. Tabbing between the boxes causes the contents of the window.status line to change; however, the JavaScript code for causing this effect differs slightly between the two. The first text box demonstrates the method for calling a JavaScript function whereas the second text box accomplishes the same task by incorporating the contents of the alertme() function inline with the event handler. Note that if you use the second technique, multiple JavaScript statements must be separated by a semicolon.

<SCRIPT LANGUAGE="JavaScript">
function alertme(strval){
     window.status=strval
     return true
}
</SCRIPT>
<FORM NAME="testform">
<INPUT TYPE="text" NAME="string1" SIZE="20" OnFocus="alertme(`This handler ¬sets the text in the status line')"><BR>
<INPUT TYPE="text" NAME="string2" SIZE="20" OnFocus="window.status='So does ¬this one!'; return true")><BR>
</FORM>


NOTE: JavaScript functions, in a method similar to C and C++, should always return a value.

JavaScript Data Types and Values

JavaScript supports the four data types listed in Table 19.2 and is a "loosely typed" language. You do not have to specify a data type when declaring a variable because type is implicitly set when assigning a value. Variable types can also be changed dynamically. For instance, you can initialize a variable as a numeric value, and later on in a routine set the variable equal to a string value without an error being generated.

When computing a result involving string data and any other data type, the non-string value usually converts into a string. For example, the following code snippet exemplifies string concatenation between a numeric and string value. The result is an alert box containing the text "Please pay the following: $22.00."

var im_a_number=22.00
var im_a_string="Please pay the following:"
alert(im_a_string+"$"+im_a_number)

Table 19.2  JavaScript Supports Four Data Types

Data Type Examples
Numeric 2, 22.23, 2001
Strings "Web Database Construction Kit", "Que Corporation"
Boolean true, false
Null (denotes absence of value) null

JavaScript Objects, Properties, and Methods

JavaScript is an object-based language. Every element in the browser can be referenced as an object. Objects have values (properties), as well as functions that can be applied to them (methods). For example, a form containing a text input field is referenced as an object. For the purpose of data validation, we are principally concerned with a property of the input field--its value. The toUpperCase() method which can be applied to the input field's value, returns the text string converted to upper case.

<HTML>
<HEAD><TITLE>My First JavaScript</TITLE></HEAD>
<FORM NAME="Myform">
<INPUT TYPE="TEXT" NAME="company" value="Fig Leaf Software">
</FORM>
</HTML>

Given the above code construct, the following references are all true:


TIP: JavaScript contains a special keyword that refers to the current object. In the prior example, if the form object company had focus, it could be referred to alternately as this, document.Myform.company, or Myform.company.

When you load an HTML document into your browser, JavaScript initializes a number of objects, listed in Table 19.3. These objects are always available.

Table 19.3  JavaScript Objects

Object Description
window The top-level object; containing properties that apply to the browser. There is also a window object for each frame defined within the browser. The topmost container is referred to as top.
location Contains the properties of the current URL. Useful for initiating page reloads.
document Your key to referencing all objects contained within the current HTML document, including form objects.

Implementing Cold Fusion Validation Functions as JavaScript

The functionality provided by CF validation functions can be mimicked by JavaScript. In the following section, you will explore methods for validating numbers, requiring data input, and checking date/time formats. You will also learn methods for trimming leading and trailing blank characters from input and checking electronic mail addresses.

There are two reasons for using these functions. From a usability standpoint, they provide immediate feedback to the user through an alert box if the data entered is invalid, shown in Figure 19.4. The user does not need to engage in a back-and-forth process of submitting form data which may then require them to hit the back button on their browser if the data is incorrect. These functions can also help minimize the amount of data checking CF must perform, which lightens the load on the Web server.

The functions provided are designed to work in tandem and follow the following general format:

Validfunction(object[,additional parameters],boolean)

where Object refers to the form object to be verified and boolean is a logical value true or false. Each function, with the exception of alltrim(), returns a value of true if the data entered is valid and false if a problem exists. The boolean parameter exists so that you may nest validation functions. Calling two validation functions for the same data element would resemble the following:

Validfunction1(object[,additional parameters],Validfunction2(object, [additional parameters],boolean));

Each validation function is contained within its own .CFM file, forming the basis of a JavaScript library whose members may be <CFINCLUDE>'d on demand.

Listing 19.2 puts these validation functions into action. The line starting "Enter a number between 1 and 10" demonstrates how you can chain these functions together to check for several different problems at the same time.

Figure 19.4  You can use JavaScript to provide immediate feedback to the user about the data they enter.

Listing 19.2  JAVAFUNC.CFM--Invoking Javascript Functions which Mimic CF Functionality

<HTML>
<HEAD>
<TITLE>JavaScript Validation Functions Examples</TITLE>
<CFINCLUDE TEMPLATE="isnumeric.cfm">
<CFINCLUDE TEMPLATE="isbetween.cfm">
<CFINCLUDE TEMPLATE="isrequired.cfm">
<CFINCLUDE TEMPLATE="alltrim.cfm">
<CFINCLUDE TEMPLATE="isdate.cfm">
<CFINCLUDE TEMPLATE="istime.cfm">
<CFINCLUDE TEMPLATE="isemail.cfm">
</HEAD>
<BODY BGCOLOR=#C0C0C0>
<H2>
JavaScript Validation Function Demonstration
<HR WIDTH=100%>
</H2>
<H3>The following functions do not use require a secondary frame for  ¬processing</H3>
<FORM ACTION="save.cfm" NAME="myform" METHOD="POST">
<TABLE>
<TR>
<TD>Enter a number (you may use comma's and decimals)</TD>
<TD>
<INPUT TYPE="TEXT" NAME="numbertest" SIZE=10 OnChange="isnumeric(this,true)">
</TD>
</TR>
<TR>
<TD>Enter a number between 1 and 10</TD>
<TD>
<INPUT TYPE="TEXT" NAME="numbertest2" SIZE=10 OnChange="isbetween(this,1,10,isnumeric(this,true))">
</TD>
</TR>
<TR>
<TD>You must type something in this box</TD>
<TD>
<INPUT TYPE="TEXT" NAME="noemptyinput" SIZE=10 ¬OnChange="isrequired(this,true)">
</TD>
</TR>
<TR>
<TD>Leading and trailing blanks will be trimmed here</TD>
<TD>
<INPUT TYPE="TEXT" NAME="nospaces" SIZE=10 OnChange="alltrim(this)">
</TD>
</TR>
<TR>
<TD>Enter a date (mm/dd/yyyy)</TD>
<TD>
<INPUT TYPE="TEXT" NAME="enterdate" SIZE=10 OnChange="isdate(this,true)">
</TD>
</TR>
<TR>
<TD>Enter a time (hh:mm:ss)</TD>
<TD>
<INPUT TYPE="TEXT" NAME="entertime" SIZE=10 OnChange="istime(this,true)">
</TD>
</TR>
<TR>
<TD>Enter an email address (username@address)</TD>
<TD>
<INPUT TYPE="TEXT" NAME="enteremail" SIZE=10 OnChange="isemail(this,true)">
</TD>
</TR>
</TABLE><BR>
</FORM>
</BODY>
</HTML>

Requiring Data Input. Cold Fusion can verify that data is entered into a field by using the form field validation suffix, _required. This functionality is implemented by creating a hidden form field using the following syntax:

<INPUT TYPE="hidden" NAME="formfieldname_required" Value="Custom Error Message">

where formfieldname is the name of the field in which you want to require input. This functionality can be easily replicated using JavaScript event handlers.

Taking a String Apart Piece By Piece--Using the Substring Method. JavaScript's substring method enables you to break a string into pieces. The syntax is:

stringvar.substring[x,y]

Stringvar is a string, and x and y are integers.

If x is less than y, substring returns a string starting with the character at position x and ending with the character before position y. The following example returns the text string Que.

var mystring="Que Corporation"
return mystring.substring[0,3]

If x is greater than y, substring returns a string starting with the character at position y and ending with the character before position x. The following example also returns the text string Que.

var mystring="Que Corporation"
return mystring.substring[3,0]

If x equals y, substring returns the empty string.

The order in which you place your x and y parameters in the substring method doesn't make a difference--using them interchangeably returns the same result.


NOTE: Individual characters in a string can be referenced from left to right starting at position zero using the function charAt(). The first character in a string, therefore, can be referenced as mystring.charAt(0) and the last character as mystring.charAt(mystring.length - 1).

Using JavaScript to Implement _required Functionality. Once you understand the substring method, insuring data input in a form field becomes a trivial matter. In Listing 19.3, a "for loop" is used in conjunction with the substring method to examine the contents of a form field, one character at a time. If any character exists in the string that is not a blank, further checking then becomes unnecessary because there's data there.

Listing 19.3  ISREQUIRED.CFM--JavaScript Can Mimic Cold Fusion's_required Functionality

<SCRIPT LANGUAGE="JavaScript">
<!--
function isrequired(obj,retval){
 if (retval) {
   retval=false
   /* check for the presence of any character besides a blank */
   for (var i=0; i<obj.value.length; i++) {
      if (obj.value.substring(i,i+1) !=" ") {
     retval=true
     	   break
     }
   }   
   if (!retval) {
      alert("This field may not be left empty")
   }
 }
 return retval
}
// -->
</SCRIPT>

Validating Data as Numeric. You can verify that data entered into a field is numeric by using the CF form field validation suffixes, _float and _integer. This functionality is implemented by creating a hidden form field using the following syntax:

<INPUT TYPE="hidden" NAME="formfieldname_integer" Value="Custom Error  ¬Message">
<INPUT TYPE="hidden" NAME="formfieldname_float" Value="Custom Error Message">

where formfieldname is the name of the field containing data that you want to verify as a number. You can duplicate these functions in JavaScript to provide a friendlier interface.

Converting Data from String to Numeric--parseInt() and parseFloat(). Before attempting to perform mathematical operations on data stored in form fields, you should first convert the values from the type string to type numeric. Otherwise, JavaScript may misinterpret the addition operator (+) in your code as a string concatenation operator, yielding unexpected results. JavaScript contains two built-in functions to accomplish this task--parseInt() and parseFloat().

Converting Strings to Integers--parseInt(). The parseInt() function parses a string and returns an integer value. The syntax for calling this function is:

parseInt(mystring[,base])

where mystring represents the character string you want to parse and the optional parameter base stipulates the radix. If the radix is left unspecified, JavaScript defaults the radix value based on the contents of the two left-most characters in mystring as specified in Table 19.4.

If the string to be parsed contains a character that is not part of the specified radix, parseInt() returns the value up to that point and ignores the offending character and all succeeding characters. ParseInt() converts all numbers to integer values without rounding.

Table 19.4  ParseInt Default Radix Information

String begins with Default Base
"0x" 16 (hexadecimal)
"0" 8 (octal)
"1"-"9" 10 (decimal)


NOTE: If the first character in the string is not in the range [0-9], both parseInt and parseFloat return a zero value on windows platforms, and NaN (Not a Number) on all other platforms. If you wish to maintain compatibility with Unix and Mac versions of Netscape, you should use the isNaN() function to check for this condition whenever invoking these two methods. Further information on isNaN() may be found in the JavaScript Special Edition reference on the CD.

Converting Strings to Floating Point--parseFloat(). The parseFloat() function evaluates a string and returns a floating point number. The syntax for calling this function is:

parseFloat(mystring)

If the string to be parsed contains a character other than a sign (+ or -), numeral (0-9), decimal point, or exponent, parseFloat() returns the value up to that point, and ignores the offending character and all succeeding characters.

Updating Data in a Form Field. Although you cannot use JavaScript to add text or form objects to a Web page once that document has completed loading, the contents of input fields may be dynamically updated by simply assigning a new value to an object's value property. Listing 19.4 demonstrates this technique by creating a form field with a value that gets incremented by 1 whenever you click the Increment button.

Listing 19.4  UPDATEVALUE.CFM--Using JavaScript, You Can Dynamically Update the Value of a Form Field

<HTML>
<HEAD><TITLE>Update Field Example</TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!--
function Incrementvalue(obj) {
     obj.value=parseInt(obj.value)+1
}
//-->
</SCRIPT>
</HEAD>
<FORM NAME="myform">
<INPUT TYPE="button" Name="Increment" VALUE="Increment!" Onclick="Incrementvalue(myform.myval)">
<INPUT TYPE="TEXT" NAME="myval" SIZE="3" VALUE="1">
</FORM></BODY></HTML>

Using JavaScript to Implement _numeric Functionality. Using JavaScript, you can write your own function to validate data input as being type numeric. Listing 19.5 converts a string into a decimal number. It also enables the user to enter commas as part of the number which is subsequently stripped out.

Listing 19.5  ISNUMERIC.CFM--Using JavaScript, You Can Validate Data as Being a Numeric Data Type

<SCRIPT LANGUAGE="Javascript">
<!--
/* This function validates a decimal numeric number      */
/* It also allows the user to type in comma's which are  */
/* stripped from string                                  */
function isnumeric(obj,retval){
   if (retval) {
      var currchar="", decimalcount=0, filteredstring="", i=0
   
	   fieldval=obj.value
 	   /* scan the string, char by char */
	   for (var i=0; i<fieldval.length; i++) {
		
	         currchar=fieldval.substring(i,i+1)
           		  /* look for valid characters */
		  if ((currchar >= "0" && currchar <= "9") |  | (currchar=="." |  | ¬currchar=="," |  | currchar=="-")) {
		        if (currchar!=",") {
			     filteredstring+=currchar
		        }
		        if (currchar=="-" && i > 0) { /* neg sign only allowed as ¬1st char */
			      retval=false
		        }
		        if (currchar==".") {
			      /* only one decimal point allowed */
           			     decimalcount++
			     if (decimalcount > 1) {
				   retval=false
		             }
		       }
		 }
	        else {
		       retval=false
	         }
	    }
	    /* replace the inputted string with a filtered string */
	    if (retval) {
	      obj.value=filteredstring
	    }
	    else {
	      alert("Invalid number") 
	    }
   }
   return retval
}
// -->
</SCRIPT>

Validating a Numeric Range. You can verify that numeric data entered into a field is within a particular range of values by using the CF form field validation suffix _range. This functionality is implemented by creating a hidden form field using the following syntax:

<INPUT TYPE="hidden" NAME="formfieldname_range_max_maxval" VALUE="MIN=1 MAX=12">

where formfieldname is the name of the field containing data that may be evaluated as being numeric. You can move this validation task over to the client by implementing the JavaScript function as in Listing 19.6.

Listing 19.6  ISBETWEEN.CFM--Using JavaScript, You Can Guarantee Numeric Data Is Entered Within a Specified Range

<SCRIPT LANGUAGE="JavaScript">
<!--
/* Make sure a number falls within a range */
function isbetween(obj,minval,maxval,retval) {
 
 if (retval) { 
  if (obj.value.length > 0) {
   if (!(parseFloat(obj.value) >= minval && parseFloat(obj.value) <= maxval)) {
     retval=false
     alert("Bad input: Number must be between "+minval+" and "+maxval)
   }
  }
 }
 return retval
}
// -->
</SCRIPT>

Validating a Date. Cold Fusion validates date formats through the form field validation suffix, _date. This functionality is implemented by creating a hidden form field using the following syntax:

<INPUT TYPE="hidden" NAME="formfieldname_date" Value="Custom Error Message">

where formfieldname is the name of the field in which you want to require data entered in date format.

This functionality is duplicated in Listing 19.7 as function isdate(). The isdate() function validates a date input in the format mm/dd/yyyy, checking for the proper range of days within a month and assuming that a year entry greater than 2100, or less than 1900, must be the result of mistyping. It further illustrates the uses of the parseInt() function and contains a complex nested if statement.

Listing 19.7  ISDATE.CFM--Using this JavaScript Function, You Can Validate that a User Has Entered a Valid Date

<SCRIPT LANGUAGE="JavaScript">
<!--
/* nochars: check for the existence of a non int character within a string */
¬function nochars(strval) {
      var retval=true
	   for (var i=0; i<strval.length;i++) {
		 if (strval.substring(i,i+1) < "0" | | strval.substring(i,i+1) > "9") {
		       retval=false
		       break
		 }
	   }
	   return retval
}
/* isdate - validate date format (mm/dd/yyyy) */
function isdate(obj,retval) {
 var month, day, year
 if (retval) {
  retval=false
  if (obj.value!=""){
	   /* check formatting of string */
	   if (obj.value.length != 10 | | obj.value.substring(2,3)!="/" | | obj.value.substring(5,6)!="/") {
	   }
	   else {
		 /* Month must be between 1 and 12 */ 
		 month=obj.value.substring(0,2)
		 if (nochars(month) && parseInt(month) > 0 && parseInt(month) <= 12) {
		       month=parseInt(month)
		       day=obj.value.substring(3,5)
		       if (nochars(day)) {
			     /* 30 days hath september, april, june, and november... */
			     day=parseInt(day)
			     if (((month!=9 && month !=4 && month!=6 && month !=11 ¬&& month !=2) && (day>=1 && day<=31)) | |
			          (month==9 | | month==4 && month==6 | | month==11  && ¬(day>=1 && day<=30)) | |
			          (month==2 && day>=1 && day<=28)) {
			           year=obj.value.substring(6,10)
			           /* limit year to range 1900 - 2100 */
			           if (nochars(year) && parseInt(year) >= 1900 && parseInt(year)<=2100) {
				         retval=true
			           }
		             }
			
		       }
	         }
      }
      if (!retval) {
        	         alert("Invalid date: You must enter a date in the format mm/dd/yyyy")
  	   }
  }
 }
 return retval
}
// -->
</SCRIPT>

Validating a Time. Cold Fusion validates time formats through the form field validation suffix, _time. This functionality is implemented by creating a hidden form field using the following syntax:

<INPUT TYPE="hidden" NAME="formfieldname_time" Value="Custom Error Message">

where formfieldname is the name of the field in which you want to validate data entered in 24 hour time format (hh:mm:ss). Listing 19.8 shows the JavaScript code replicating this functionality using an algorithm similar to the one used to validate dates.

Listing 19.8  ISTIME.CFM--This JavaScript Function Ensures the User Enters a Properly Formatted Time in 24-Hour Format

<SCRIPT LANGUAGE="JavaScript">
<!--
/* istime - validate time format (hh:mm:ss)              */
/* note: requires function alltrim() in file alltrim.cfm */
/* it also requires nochars() in file isdate.cfm */
function istime(obj,retval) {
 if (retval) {
  retval=false
  var hours, minutes, seconds
  obj=alltrim(obj)
  if (obj.value.length==5) { /* seconds are optional */
	   obj.value+=":00"
  }
     
  if (obj.value!=""){
	   /* check formatting of string */
	   if (obj.value.length != 8 | | obj.value.substring(2,3)!=":" | | obj.value.substring(5,6)!=":") {
	   }
	   else {
		  /* Hours must be between 0 and 24 */ 
		  hours=obj.value.substring(0,2)
		  if (nochars(hours) && parseInt(hours) >= 0 && parseInt(hours) < 24) {
			hours=parseInt(hours)
			minutes=obj.value.substring(3,5)
			if (nochars(minutes)) {
			      minutes=parseInt(minutes)
			      if (minutes >=0 && minutes <=59) {
				    seconds=obj.value.substring(6,8)
				    /* seconds between 0 and 59 */
				    if (nochars(seconds) && parseInt(seconds) >= 0 && parseInt(seconds)<=59) {
					  retval=true
				    }
			      }
			
		        }
		 }
	   }
	   if (!retval) {
		 alert("Invalid : You must enter a time 24 hour format (hh:mm:ss) ¬or (hh:mm)")
	   }
  }
 }
 return retval
}
// -->
</SCRIPT>

Additional JavaScript Validation Functions

Using JavaScript and the techniques presented in this chapter, you can create your own, special purpose validation functions and develop a reusable toolbox of data-checking algorithms.


Trimming Leading and Trailing Blanks. When validating data, it is often useful to remove any leading or trailing blanks in the data input prior to validating the format of the data. The alltrim() algorithm presented in Listing 19.9 strips all leading and trailing blanks from data in a form field by scanning the string value from left to right and finding the location of the left-most character that is not a space. It then scans the string from right to left looking for the location of the first non-space character. Once it has determined these two locations, the substring method is invoked to "cut out" the part of the string containing alphanumeric characters.

Listing 19.9  ALLTRIM.CFM--Using JavaScript, You Can Trim Leading and Trailing Spaces from Input Data

<SCRIPT LANGUAGE="JavaScript">
<!--
/* Trim leading and trailing blanks from an input field */
function alltrim(obj){
   var trimmedstring="",startpos=0, endpos=obj.value.length - 1
   /* find start position of string */	
   while (startpos<=obj.value.length && obj.value.substring(startpos, ¬startpos+1)==" ") {
 	   startpos++
   }
   /* null string */
   if (endpos == -1) {
     endpos=0
   }
   /* find end position of string */
   while (endpos >= 0 && obj.value.substring(endpos,endpos+1)==" ") {
	   endpos--
   }
   /* replace value with trimmed string */
   obj.value=obj.value.substring(startpos,endpos+1)
   return obj
}
// -->
</SCRIPT>

Validating an Electronic Mail Address. We'd certainly like to develop a robust method for determining the validity of an electronic mail address instead of having a mail server bounce an undeliverable e-mail back to us hours later, if at all. Implementing this functionality is a bit beyond JavaScript's capabilities, however, and we are left with only being able to make sure an address is properly formatted.

Using the indexOf Method to Search for a String Within a String. The indexOf method returns the beginning numeric position of the first occurrence of a string of characters contained within another character expression. The syntax for invoking this functionality follows:

stringName.indexOf(TargetString, [startlocation])

StringName is the string to be searched, TargetString is the string of characters which may be contained within stringName, and the optional parameter startlocation is the starting position in stringName where the search begins.

IndexOf returns an integer corresponding to the position in stringName where the first character in the character expression TargetString was found. If the character expression is not found, IndexOf returns -1.

In the following example, the variable location would be initialized to a value of 14.

Var mystring="How now brown cow!"
var location=mystring.indexOf("cow")

Searching for the @ Symbol. One shared trait between electronic mail messages on the Internet is that they all contain an @ sign in their address. Whether you're sending mail to mrpresident@whitehouse.gov or drgui@microsoft.com, the format is always the same. Therefore, it makes sense to check for the existence of an @ character when requesting someone's e-mail address in a form. Listing 19.10 invokes the indexOf method, to accomplish this task.

Listing 19.10  ISEMAIL.CFM--Simple Electronic Mail Address Validation

<SCRIPT LANGUAGE="JavaScript">
<!--
function isemail(obj,retval){
 
 if (retval) {
   if (obj.value.length != 0) {
      if (obj.value.indexOf(`@')==-1) {
		 alert("You entered an invalid email address!")
 		 retval=false
	   }
   }
 }
 return retval
}
//-->
</SCRIPT>

Things You Can't Do in JavaScript

There are a plethora of uses for JavaScript, but it should not be considered a panacea for data validation. There are limitations to what you can accomplish using this language. One restriction is that you may not have a JavaScript function that originated on one host, execute on a different host. This comes into play when attempting to validate URLs (see Figure 19.5). The following function, validateurl, accepts a URL entered into a text field in a primary frame and then attempts to actually load the URL into a secondary frame. By comparing the host name of the loaded document in the secondary frame to the URL specified in the primary frame, it validates whether a valid entry was input.

Unfortunately, once the URL to be validated is loaded into the secondary frame, Netscape registers the host URL in the secondary frame as having current browser focus and as such, will not let the comparison function that originated in the primary frame execute (see Listing 19.11).

Listing 19.11  ISVALIDURL.CFM--Validating a URL

<SCRIPT LANGUAGE="JavaScript">
<!--
/**********************************************************************
      These functions work in MSIE 3.0, but not in Netscape 3.0
**********************************************************************/
/**********************************************************************
  validateurl - checks to make sure the host name that was returned
                is the same as the one that was entered as input.
		     If not, an alert with some diagnostic info is displayed	
  parameters: objvalue - data entered by user
              targframevalue - name of frame where URL load was attempted              
***********************************************************************/
function validateurl(objvalue,targframevalue) {
   var cmdstr="top."+targframevalue+".location.hostname", retval=true
   locatedhost=eval(cmdstr)
 
   if (objvalue.indexOf(locatedhost)==-1){
 						/* Hostname not found */
      retval=false
      errmsg="Host name not found.\n"
	   if (objvalue.indexOf(".edu")==-1 && 
	       objvalue.indexOf(".com")==-1 &&
	       objvalue.indexOf(".org")==-1 &&
	       objvalue.indexOf(".mil")==-1 &&
	       objvalue.indexOf(".gov")==-1) {
		 errmsg+="Hint: Most valid urls end in .edu, .com, .org, .mil, or .gov"
	   }
    
   }
   if (!retval) {
      alert(errmsg)
   }
   else {
     window.status="URL is valid" 
   }
}
/*********************************************************************** 
   isvalidurl -- this attempts to load the inputted url into a frame,
   then sets a timer to validate that the page has actually loaded.
   parameters: obj -- input object containing URL
		    targframe -- name of frame to attempt to load url into
************************************************************************/
function isvalidurl(obj,targframe) {
   var errmsg="", retval=true
   var locatedhost, timerid, currenttime,exittime
   var newobj=obj, newtarg=targframe
   
   var cmdstring="top."+targframe+".location.href="+"'"+obj.value+"'"
 
   window.status="Validating URL.  Please Wait."   
 
   eval(cmdstring)
  
   cmdstring='setTimeout("validateurl(` +  "`" + obj.value + "`,'" + ¬targframe +  "`)" 
   
   cmdstring+='"'+",5000)"  
   eval(cmdstring)
   return obj
}
// -->
</SCRIPT>

Figure 19.5  The functions in this listing use a unique method to validate URLs in JSCRIPT/MSIE 3.0, but generate this security violation error in Netscape Navigator 3.0.

Cold Fusion Interaction with Scripting Languages

CF and scripting languages exist in their own separate domains. Cold Fusion has no built-in facilities for interacting with JavaScript or VBScript and vice-versa. You cannot "mix and match" variables declared in one language with constructs created in another. For example, the following code snippet would result in a CF Variable x1 not found error:

<SCRIPT LANGUAGE="JavaScript">
var x1=10
<CFSET #x2#=20>
<CFSET #x2#=#x1#=#x2#>
</SCRIPT>

Similarly, the following code would result in a JavaScript Variable not defined error:

<SCRIPT LANGUAGE="JavaScript">
var x1=10
<CFSET #x2#=20>
x1=x1+#x2#
</SCRIPT>

To get these two disparate platforms to talk to each other involves the clever use of JavaScript to pass values to CF through form fields and URLs. Data may be transferred from CF into JavaScript code by using <CFOUTPUT> to actually output JavaScript code segments.

Passing Values to Cold Fusion Using JavaScript

Cold Fusion cannot access values contained within JavaScript variables. CF does, however, recognize the existence of submitted form fields and parameters passed on the URL; so, the "trick" to transferring data stored in JavaScript to CF variables involves either writing JavaScript variable contents to form fields and then submitting the form to CF or by having JavaScript dynamically create a URL, complete with the parameters you want to pass to CF. Either method requires a document reload.


Creating Self-modifying Code--the eval() Function. Perhaps JavaScript's most powerful feature is the ability to create self-modifying code. This is accomplished using the built-in function, eval(). The syntax for the function is:

eval(stringval)

where Stringval is a string representing a valid JavaScript expression, statement, or sequence of statements.

In the following example, a valid JavaScript statement is stuffed into a string variable. Using the eval function causes this statement to execute with the end result being an alert box displayed on screen containing the text I have been evaluated!

<SCRIPT LANGUAGE="JavaScript">
var cmdstr="alert(`"
cmdstr+="I have been evaluated"
cmdstr+="')"
eval(cmdstr)  // JavaScript executes the statement: alert(`I have been ¬evaluated')
</SCRIPT>

Passing JavaScript Values as URL Parameters. One method for passing JavaScript variables to Cold Fusion uses JavaScript string functions to build a custom URL, incorporating the JavaScript variable and value as a URL parameter. In Listing 19.12 you are prompted to enter a numeric value between -1 and 1. This launches the JavaScript function submitit() which calculates the arcsine of the value you entered. A URL is then cobbled together including the names and values of the JavaScript variables as URL parameters. The URL then loads using the eval() function.

Listing 19.12  INTERACT.CFM--Using eval() to Pass JavaScript Variables into the CF Domain

<HTML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function submitit(){
  
  /* init the JavaScript variable to send to the next form */
  var arcsine=Math.asin(document.myform.inputval.value)  
  
  /* build the JavaScript command to activate the destination URL */
  var submitlocation="result1.cfm"
  /*
     attach the JavaScript variables and values to transfer from the
     JavaScript domain to the CF domain 
  */
  submitlocation+="&inputval="+document.myform.inputval.value
  submitlocation+="&arcsine="+arcsine
  var cmdstr="document.location.href='"+submitlocation+"'"
  /* activate the command to load the destination url */
  eval(cmdstr)
}
//-->
</SCRIPT>
<BODY BGCOLOR=#C0C0C0>
<H2>Passing values from JavaScript to Cold Fusion
<HR WIDTH="100%">
</H2>
<FORM NAME="myform">
Pick a number between -1 and 1 and press [TAB]:
<INPUT TYPE="text" NAME="inputval" SIZE=5 VALUE="" OnChange="submitit()"><BR>
<INPUT TYPE="SUBMIT" OnClick="submitit()">
</FORM>
</BODY>
</HTML>


CAUTION: You should only use this method when the data to be passed on the URL does not contain any white space; otherwise, the value truncates at the first blank character in the string.

The Hidden Form Field Technique. A secondary, and more robust method for transferring the values of JavaScript variables to Cold Fusion uses hidden fields. Listing 19.13 replicates the functionality of the prior listing--you enter a number, its arcsine calculates and then passes to a form. Note the differences between the two listings.

This methodology requires the presence of a hidden form field whose value is dynamically set by a JavaScript function. This hidden field is then passed to CF (along with every other input object on the page) during form submission.

Listing 19.13  INTERACT2.CFM--Using Hidden Form Fields to Transfer JavaScript Variables to Cold Fusion

<HTML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function stuffvalue(){
  
  /* 
     init the JavaScript variable to send to the next form    
  */
 
  var arcsine=Math.asin(document.myform.inputval.value)  
  
  /* 
     stuff the JavaScript variable's value into a hidden field 
     which will be transferred to CF in the POST operation
  */
  document.myform.arcsine.value=arcsine
}
//-->
</SCRIPT>
<BODY BGCOLOR=#C0C0C0>
<H2>Passing values from JavaScript to Cold Fusion (hidden field method)
<HR WIDTH="100%">
</H2>
<FORM NAME="myform" ACTION="result1.cfm" METHOD="POST">
Pick a number between -1 and 1:
<INPUT TYPE="hidden" NAME="arcsine" VALUE=0>
<INPUT TYPE="text" NAME="inputval" SIZE=5 VALUE="" OnChange="stuffvalue()"><BR>
<INPUT TYPE="SUBMIT">
</FORM>
</BODY>
</HTML>

Using Cold Fusion to Generate JavaScript

Passing CF variables to JavaScript involves using <CFOUTPUT> to output JavaScript code. In Listing 19.14, a CF variable is set to the number 5. This value is then transferred into the JavaScript domain by outputting the value as part of a JavaScript variable initialization statement.

Listing 19.14  INTERACT3.CFM--Importing CF Values into the JavaScript Domain

<HTML>
<HEAD><TITLE>CF transferring values to JavaScript</TITLE>
<CFSET #formvalue# = 5>
<SCRIPT LANGUAGE="JavaScript">
<!--
      <CFOUTPUT> 
	   var formvalue=#variables.formvalue#
        </CFOUTPUT>
	     alert("The CF value, converted to a JavaScript variable is:" + formvalue)
// -->
</SCRIPT>
</HEAD>
</BODY>
</HTML>

Combining Server and Client-Side Validation Techniques

You can use JavaScript and CF to create event driven data lookups. Figure 19.6 applies nearly all the techniques described in this chapter to create a generalized mechanism for on-the-fly data retrieval and validation.

Figure 19.6  You can use JavaScript to activate a CF query that automatically fills in form fields on-the-fly.

Listing 19.15  LOOKUP.CFM--You Can Use JavaScript to Launch a Cold Fusion Template

<SCRIPT LANGUAGE="JavaScript">
<!--
/* 
    lookup() - this function is a "wrapper" for firing off a CF select query 
*/
function
lookup(obj, datasource, tablename, sourcewindow, targwindow, getfieldname, ¬targetfield, keyfield,formid) {
   
   var cmdstr=""
   cmdstr="top."+targwindow+".location.href='/cgi/dbml.exe?template=/que/    addvalid/JavaScript/cflookup.cfm"
   cmdstr+="&keyfieldvalue="+obj.value   /* value to search for          */
   cmdstr+="&datasource="+datasource     /* datasource for query         */
   cmdstr+="&tablename="+tablename       /* tablename for CF query       */
   cmdstr+="&sourcewindow="+sourcewindow /* window name where form exists*/
   cmdstr+="&targwindow="+targwindow     /* window name to run cf query  */
   cmdstr+="&getfieldname="+getfieldname /* name of field to retrieve    */
   cmdstr+="&targetfield="+targetfield   /* name of field to set value   */
   cmdstr+="&keyfield="+keyfield         /* name of data field to search */
   cmdstr+="&formref="+formid            /* array offset of form         */
   cmdstr+="'"
   eval(cmdstr)
   return true
}
//-->
</SCRIPT>

Listing 19.16  CFLOOKUP.CFM--Using CF and JavaScript

<CFQUERY NAME="getinfo" DATASOURCE="#datasource#">
    SELECT #getfieldname# as queryresult
      FROM #tablename#
     WHERE #keyfield#=#keyfieldvalue#
</CFQUERY>
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<--
<CFOUTPUT>
<CFIF #getinfo.recordcount# is 1>
top.#sourcewindow#.document.forms[#formref#].#targetfield#.value="#getinfo. ¬queryresult#"
<CFELSE>
    top.#sourcewindow#.document.forms[#formref#].#targetfield#.value="*Not 		    Found"
</CFIF>
</CFOUTPUT>
// -->
</SCRIPT>
</HEAD>
<BODY>
<CENTER><H2>CF Lookup Activated</H2></CENTER>
</BODY>
</HTML>


NOTE: One restriction on function lookup( ) is it will only work when keyfield is a number. To convert the function for use with a keyfield string value, change the sql line to read WHERE #keyfield#="#keyfieldvalue#.

From Here...

JavaScript can be a powerful ally in validating user input, however, keep aware that some JavaScript functions are browser specific and most older browsers do not support them. Using Cold Fusion to evaluate the HTTP_USER_AGENT CGI variable can help you develop browser-specific templates but this has its own pitfall in that you must support more than one code set.


Previous chapterNext chapterContents

© Copyright, Macmillan Computer Publishing. All rights reserved.