As promised, in this section we will examine reusable methods to create HTML forms with the proper form fields, complete with client-side form validation. These methods will hide the specific details of properly naming form fields and will not bother the developer with creating client-side form validation routines.
Usually,
creating a form is a trivial task; it’s just a matter of HTML
coding. However, due to our reusable server-side validation code,
creating a form has become a much more complex issue. When using a
global server-side form validation page that all forms initially
submit to, all the forms need to follow a certain standard.
Specifically, the NAME
of each form element that
requires form validation must contain an exclamation point followed
by the validation regular expression. Furthermore, the form’s
ACTION
property must direct to the validation
page ( /CODEREUSE/ValidateForm.asp
) and pass two
HIDDEN
variables:
Collection
and
Redirect
.
Remembering these specific details is cumbersome and serves as an
easy place to make a mistake, resulting in a bug. Also, if other
developers are to be working on creating the HTML forms, they will be
less familiar with the conventions specified by the server-side form
validation script, /CODEREUSE/ValidateForm.asp
.
As discussed earlier, client-side form validation is a nice option, although not as critical as server-side form validation. As with server-side form validation, client-side form validation lends itself to reuse.
To reduce implementation complexity and provide a black box-like interface, we’ll use classes! Two classes can be created that will provide the following benefits:
Provide the end developer with an easy interface to create forms that contain complex implementation details.
Provide automatic code generation for client-side form validation.
The first class defines a form field element as an object. Each form
field object has a certain set of
properties: NAME
,
TYPE
, SIZE
, and
VALUE
are four standard ones. For our custom
server-side validation routines, an optional validation regular
expression is yet another property. Our rather simplistic form field
class, FormElement
, contains the following definition,
which is stored in the file
CODEREUSEFormCreation.Class.asp
:
<% Class FormElement '****************** PROPERTIES ******************** Private strName Private strRegExp Private strType Private strPreHTML Private strPostHTML Private strSize Private strValue '************************************************** '************* PROPERTY LET STATMENTS ************* Public Property Let Name(str) strName = str End Property Public Property Let RegularExpression(str) strRegExp = str End Property Public Property Let ElementType(str) 'Only one of six types possible: SELECT, TEXTAREA, TEXT, ' RADIO, HIDDEN, or CHECKBOX (TEXT is the default) If Ucase(str) = "TEXT" OR Ucase(str) = "SELECT" _ OR Ucase(str) = "TEXTAREA" OR Ucase(str) = "RADIO" _ OR Ucase(str) = "CHECKBOX" OR Ucase(str) = "HIDDEN" then strType = str Else strType = "TEXT" 'TEXT is the default type End If End Property Public Property Let Size(str) strSize = str End Property Public Property Let PreHTML(str) strPreHTML = str End Property Public Property Let PostHTML(str) strPostHTML = str End Property Public Property Let Value(str) strValue = str End Property '************************************************** '************* PROPERTY GET STATMENTS ************* Public Property Get Name( ) Name = strName End Property Public Property Get RegularExpression( ) RegularExpression = strRegExp End Property Public Property Get ElementType( ) ElementType = strType End Property Public Property Get Size( ) Size = strSize End Property Public Property Get PreHTML( ) PreHTML = strPreHTML End Property Public Property Get PostHTML( ) PostHTML = strPostHTML End Property Public Property Get Value( ) Value = strValue End Property '************************************************** '********************* METHODS ******************** Public Sub Clear( ) strName = "" strRegExp = "" strType = "" strSize = "" strPreHTML = "" strPostHTML = "" strValue = "" End Sub '************************************************** End Class %>
A FormElement
class instance represents a discrete
form field element in a form. This implementation of
FormElement
contains only a small subset of the
properties a form field element can contain. If your web site
requires more elegant form fields, add the needed form field
properties in the above class. The following list shows the various
properties of the FormElement
class:
Specifies the NAME
property of the form element.
It is essential this property is specified. Furthermore, it is
recommended that you give the NAME
property an
English-like name, since if there is a validation error, this
property is reported in the error message.
Specifies the regular expression validation code. Remember the validation routine will search to see if the user’s input matches this regular expression.
Specifies the TYPE
for the form
element. This can have one of six possible values:
SELECT
, TEXTAREA
,
TEXT
, RADIO
,
CHECKBOX
, or HIDDEN
, which
create a list box, a multi-row text box, a single-row text box, a
radio button, a checkbox, or a hidden form field, respectively.
This property specifies any HTML that should occur before the actual
INPUT
tag.
This property specifies any HTML that should occur after the actual
INPUT
tag.
This property specifies the
SIZE
property for the form element. In a
multi-row text box, there are as many columns as specified by the
Size property and one-fourth as many rows.
This property specifies the
VALUE
property of the
INPUT
tag. It is meaningless if you are creating a
list box, multi-row text box, radio button, or checkbox. The Value
property is very useful when creating HIDDEN
form
fields.
The FormElement
class uses the Clear method, as
described in the following definition:
The Clear method erases all of the property values. Normally such a method wouldn’t be needed. The Adding Form Elements later in this chapter explains why I chose to supply such a method.
We’ll look at how to use the FormElement
class and its properties and methods once we examine the
GenerateForm
class.
GenerateForm
is the class used to create the HTML
that will physically construct the form on the users’ browsers.
Each function of GenerateForm
’s properties
is outlined here:
Specifies whether to submit the form using an
ACTION
of POST
(the default) or
GET
. To use GET
, Collection
must be set equal to QueryString. If it equals any other value, the
form will submit with an ACTION
of
POST
.
The URL of the actual form-processing script. Once the data is
validated by /CODEREUSE/ValidateForm.asp
, this
is the page the user is passed to.
Specifies the NAME
property of the form. If not
specified, frmForm1
is used. If you plan
to use the GenerateForm
class to create more than
one form on an HTML page, it is essential that each form have its
own, unique FormName for client-side form-validation purposes.
Specifies the URL of the server-side form validation script. Set to
/CODEREUSE/ValidateForm.asp
in the Initialize
event, but can be modified.
The title for the form’s submit button. The title, if not specified, defaults to “Submit Query!”
This property is indirectly write-only. This property is a Dictionary object that contains zero to many HTML strings that correspond to form field elements. To add a new form field element, use the AddElement method.
The following list discusses the GenerateForm
class’s
methods:
objFormElement
)Adds a form field element to objFormElementDict.
objFormElement
is expected to be an
instance of the FormElement
class. A more thorough
discussion of why this technique is used to add a form element
appears in a later sidebar.
Returns the HTML that will generate a form specified by the form field elements in objFormElementDict.
Returns the client-side JavaScript code that will validate the form field inputs. The client-side JavaScript takes advantage of regular expressions; hence the client-side validation code will only work properly in browsers that support JavaScript 1.2 or greater: Internet Explorer or Netscape Navigator 4.0 and up.
strTitle
)Returns the entire HTML document in one string. Only useful if the
HTML page will contain one form and one form only. The
strTitle
parameter displays a title at the
beginning of the HTML page (right after the
<BODY>
tag).
GenerateHTMLDocument(X
) is synonymous
with:
<HTML><HEAD>GenerateValidation( )
</HEAD><BODY>X
GenerateForm( )
</BODY></HTML>
The GenerateForm
class definition, which is listed
in Example 5.5 and is also stored in the file
CODEREUSEFormCreation.Class.asp
along with the
definition of the FormElement
class, is fairly
straightforward and easy to use. To create a form, two object
instances are needed: an instance of GenerateForm
and an instance of FormElement
. Start by creating
the GenerateForm
instance and set its properties.
Next, create a single FormElement
instance, set
the needed properties in the FormElement
instance,
and call the AddElement method of the GenerateForm
instance, passing in the FormElement
instance.
Finally, call the FormElement
instance’s
Clear method and repeat the previous three steps for each element in
the form.
Example 5-5. The GenerateForm Class Definition
<% Class GenerateForm '****************** PROPERTIES ******************** Private strRedirect Private strCollection Private strFormAction Private objFormElementDict Private strFormName Private strSubmitTitle '************************************************** '************** INITIALIZE/TERMINATE ************** Private Sub Class_Initialize( ) 'Set the default property values strCollection = "FORM" strFormAction = "/CODEREUSE/ValidateForm.asp" strFormName = "frmForm1" strRedirect = Request.ServerVariables("SCRIPT_NAME") strSubmitTitle = "Submit Query!" Set objFormElementDict = CreateObject("Scripting.Dictionary") End Sub Private Sub Class_Terminate( ) Set objFormElementDict = Nothing ' Clean up End Sub '************************************************** '************* PROPERTY LET STATMENTS ************* Public Property Let Collection(str) 'Set the strCollection private property, making sure it is 'set to either QueryString or Form (default to Form) If Ucase(str) = "QUERYSTRING" then strCollection = "QueryString" Else strCollection = "Form" End If End Property Public Property Let Redirect(str) 'Set the strRedirect private property; if trying to assign it 'a blank string, assign it the value of the current ASP page If Len(str) = 0 then strRedirect = Request.ServerVariables("SCRIPT_NAME") Else strRedirect = str End If End Property Public Property Let FormAction(str) 'Set the strFormAction private property strFormAction = str End Property Public Property Let FormName(str) 'Set the strFormName private property strFormName = str End Property Public Property Let SubmitTitle(str) 'Set the strSubmitTitle private property If Len(str) = 0 then strSubmitTitle = "Submit Query!" Else strSubmitTitle = str End If End Property '************************************************** '************* PROPERTY GET STATMENTS ************* Public Property Get Collection( ) Collection = strCollection End Property Public Property Get Redirect( ) Redirect = strRedirect End Property Public Property Get FormAction( ) FormAction = strFormAction End Property Public Property Get FormName( ) FormName = strFormName End Property Public Property Get SubmitTitle( ) SubmitTitle = strSubmitTitle End Property '************************************************** '********************* METHODS ******************** Public Function AddElement(objFormElement) 'Adds a form field element to the objFormElementDict object 'Expects to be passed a valid objFormElement instance Dim strHTML, strTechnicalName 'Determine if this form field needs to be validated If Len(objFormElement.RegularExpression) > 0 then strTechnicalName = objFormElement.Name & "!" & _ objFormElement.RegularExpression Else strTechnicalName = objFormElement.Name End If 'Determine what form field type we are dealing with If objFormElement.ElementType = "SELECT" then strHTML = objFormElement.PreHTML & vbCrLf & _ "<SELECT NAME=""" & objFormElement.Name & """" If Len(objFormElement.Size) > 0 then strHTML = strHTML & " SIZE=" & objFormElement.Size End If strHTML = strHTML & ">" & vbCrLf & _ objFormElement.PostHTML & _ vbCrLf & "</SELECT>" & vbCrLf & vbCrLf Elseif objFormElement.ElementType = "TEXTAREA" then strHTML = objFormElement.PreHTML & vbCrLf & _ "<TEXTAREA NAME=""" & strTechnicalName & """" If Len(objFormElement.Size) > 0 then strHTML = strHTML & " COLS=" & objFormElement.Size & _ " ROWS=" & objFormElement.Size / 4 End If strHTML = strHTML & "></TEXTAREA>" & _ vbCrLf & objFormElement.PostHTML & _ vbCrLf & vbCrLf Else 'must be one of the other types strHTML = objFormElement.PreHTML & vbCrLf & _ "<INPUT NAME=""" & strTechnicalName & """" If Len(objFormElement.Size) > 0 then strHTML = strHTML & " SIZE=" & objFormElement.Size End If If Len(objFormElement.Value) > 0 then strHTML = strHTML & " VALUE=""" & objFormElement.Value & """" End If strHTML = strHTML & " TYPE=" & objFormElement.ElementType & _ ">" & vbCrLf & objFormElement.PostHTML & _ vbCrLf & vbCrLf End If 'Add the HTML to the FormElement dictionary objFormElementDict.Add strTechnicalName, strHTML End Function Public Function GenerateForm( ) 'Iterates through the objFormElementDict collection and 'generates the resulting form Dim strResultingForm strResultingForm = "<FORM NAME=""" & strFormName & _ """ METHOD=" If strCollection = "QueryString" then strResultingForm = strResultingForm & "GET" Else strResultingForm = strResultingForm & "POST" End If strResultingForm = strResultingForm & " ACTION=""" & _ strFormAction & """ ONSUBMIT=""return ValidateData( );"">" & _ vbCrLf 'Add the HIDDEN form variables strResultingForm = strResultingForm & vbTab & "<INPUT TYPE=HIDDEN " & _ "NAME=Collection VALUE=""" & strCollection & """>" & vbCrLf & _ vbTab & "<INPUT TYPE=HIDDEN NAME=Redirect VALUE=""" & _ strRedirect & """>" & vbCrLf 'Iterate through the form element dictionary, outputting the 'form field elements Dim strName For Each strName in objFormElementDict strResultingForm = strResultingForm & vbTab & objFormElementDict(strName) Next strResultingForm = strResultingForm & "<P><INPUT TYPE=SUBMIT VALUE=""" & _ strSubmitTitle & """>" & vbCrLf & vbCrLf strResultingForm = strResultingForm & "</FORM>" & vbCrLf & vbCrLf GenerateForm = strResultingForm End Function Public Function GenerateValidation( ) 'Creates the client-side validation code Dim strCode strCode = "<SCRIPT LANGUAGE=""JavaScript"">" & vbCrLf & "<!--" & vbCrLf & _ "function ValidateData( )" & vbCrLf & "{" & vbCrLf & _ vbTab & "var iLoop;" & vbCrLf & vbCrLf 'Now, for each form element that contains regular expression code, 'prepare it for validation! Dim strName, strRegExp For Each strName in objFormElementDict If InStr(1,strName,"!") then 'We have form validation!! Grab the regexp strRegExp = Right(strName, Len(strName) - InStr(1,strName,"!")) strCode = strCode & vbTab & "if (document.forms['" & strFormName & _ "'].elements['" & Replace(strName,"","\") & _ "'].value.search(/" & strRegExp & "/) == -1) {" & vbCrLf & _ vbTab & vbTab & "alert('" & Left(strName, InStr(1,strName,"!") _ - 1) & " is not valid.')," & vbCrLf & vbTab & vbTab & _ "return false;" & vbCrLf & vbTab & "}" & vbCrLf End If Next strCode = strCode & vbCrLf & vbTab & "return true;" & vbCrLf strCode = strCode & "}" & vbCrLf strCode = strCode & vbCrLf & "// -->" & vbCrLf & "</SCRIPT>" & vbCrLf GenerateValidation = strCode End Function Public Function GenerateHTMLDocument(strTitleHTML) 'This method generates the HTML/BODY tags, the form and client-side 'form validation all in one call Dim strResultHTML strResultHTML = "<HTML><HEAD>" & vbCrLf & GenerateValidation( ) & _ "</HEAD>" & vbCrLf strResultHTML = strResultHTML & "<BODY>" & vbCrLf & strTitleHTML & _ vbCrLf & GenerateForm( ) & vbCrLf & "</BODY></HTML>" GenerateHTMLDocument = strResultHTML End Function '************************************************** End Class %>
For example, the following code will create a form with four form
fields (two text boxes, a text area, and a list box). The first two
text boxes are validated on the client side when the form is
submitted (and will also be subject to validation on the server side
when submitted to /CODEREUSE/ValidateForm.asp
).
For the example, the two class definitions were placed in an separate
file and included in the