reptile7's JavaScript blog
Wednesday, January 12, 2011
Further Adventures in Form Validation, Part 1
Blog Entry #202

Today's post will return us to the realm of form validation as we take up HTML Goodies' "Bring Your Forms to Life With JavaScript" tutorial, which is authored by Kris Hadlock and, like the "How to Populate Fields from New Windows Using JavaScript" tutorial we've been discussing in the last few entries, is a import.

"Bring Your Forms to Life With JavaScript" offers a liveforms/ file package, downloadable here, that codes a user registration form - the form holds fields for a user's first name, last name, street address, etc. - and individually validates a user's inputs for that form. For a valid field input, a [The 'check' image for a valid input] check.gif image is placed next to the field, whereas for an invalid input, an [The 'x' image for an invalid input] x.gif image is placed next to the field - that's how we'll 'bring the form to life'. When the values of the form's required fields are all in order, then an initially disabled submit button for sending those values to a processing agent is activated.

The author provides a tutorial demo here. As regards the OS X GUI browsers on my computer, the original demo works fine with Firefox, Opera, Camino, and Netscape 9, but is was problematic with Safari, Chrome, and MSIE 5.2.3 for reasons we will elaborate in due course.
November 2016 Update: Inexplicably, the Validator.js and utils.js importations (vide infra) have been removed from the demo.html source; as a result, the demo is now dysfunctional for all JavaScript-enabled browsers.

Code overview

The liveforms/ package comprises an img/ folder, an index.html file, and a js/ folder.
(1) The img/ folder contains the check.gif and x.gif images.
(2) The index.html file contains the registration form code.
(3) The js/ folder contains Validator.js and utils.js script files that jointly carry out the aforedescribed validation of the index.html form (hereafter the liveForm form, per the value of its id attribute).

The liveForm form holds
(a-f) six text boxes for respectively entering a first name, a last name, an email address, a company name, a street address, and a zip code, and also a
(g) 50-option selection list for choosing a state.
The user is required to input a value for all of these fields excepting the company name field. The form concludes with a
(h) submit button that is disabled for JavaScript-enabled users but is enabled for sans-JavaScript users.

The Validator.js script does the lion's share of the validation work via seven methods associated with a custom Validator object. For its part, the utils.js script comprises five auxiliary functions, one of which, ac( ), is never called. These scripts employ an impressive range of JavaScript and DOM features, as we'll see below.

Setting the stage

So, let's say we visit the aforelinked tutorial demo page. The action begins in the document head with the import of the utils.js and Validator.js scripts:

<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/Validator.js"></script>

At this time, the Validator.js script creates an empty Object object and gives it a Validator identifier

var Validator = new Object( );

and then associates with that object a series of functions, which thereby become methods of that object, to be detailed later; there is no top-level code in the utils.js script. We previously worked with a new Object( ) object in the guitar chord chart script of HTML Goodies' JavaScript Script Tips #56-59; we assigned properties to that object, as we'll also do to Validator, but didn't equip it with any methods. (There are other ways to create custom JavaScript objects, and it is clear from the "Working with objects" chapter of the JavaScript 1.5 Core Guide that the new Object( ) route is not Mozilla's preferred means of doing so, but let's just go with the flow for the time being.)

Let's move now to the bottom of the demo.html page. If we are sans-JavaScript users, we'll see an active button via:

<div id="innerFieldset">
<noscript><input id="submit" type="submit" value="Register" class="action" /></noscript>

• I'm pretty sure we've never discussed the noscript element before - this element allows authors to provide alternate content when a script is not executed. Its use here is unnecessary, at least vis-à-vis a visual browser (I don't know if non-visual browsers give it a special rendering); moreover, the noscript element's %block; content model is violated by the above code.
• No use is made of the input element's class="action" attribute.
• Somewhat amusingly, the button, which lies outside the liveForm fieldset, is horizontally stretched most of the way across the viewport by a width:90% style declaration:

BTW, the button's containing block is the id="innerFieldset" div element and not the noscript element, even though the latter is a block-level element.

And what happens if we are JavaScript-enabled users, as is more likely to be the case? The innerFieldset div element is followed by a script element

<script type="text/javascript">
gebid('innerFieldset').innerHTML = '<input id="submit" type="submit" value="Register" style="width: 100px;" disabled="true" />';

which calls the gebid( ) function of the utils.js script

function gebid(i) {
    try {
        return document.getElementById(i); }
    catch(err) {
        return null; } }

which 'gets' the innerFieldset div element and returns it to the calling script element, which sets its innerHTML to a width:100px, disabled submit button.

• We previously discussed an application of the try...catch statement in the Try me, catch me subsection of Blog Entry #165. Are there any browsers out there that support the try...catch statement but not the getElementById( ) method? I don't think so, but I could be wrong about that.
HTML boolean attributes such as disabled (and selected - cf. the state selection list code) are not set to true/false à la JavaScript and DOM properties; rather, they may legally take a single value: the name of the attribute itself (e.g., selected='selected'). If a document is served as HTML (vis-à-vis XHTML), then a boolean attribute should be specified in its minimized form:

<input id="submit" type="submit" value="Register" style="width: 100px;" disabled />

When the demo.html page has finished loading, an onload event handler

<body onload="Validator.Initialize('liveForm', 6, 'submit', 'img/check.gif', 'img/x.gif');">

calls the Initialize( ) method of the Validator object and passes thereto a set of five parameters.

Validator.Initialize = function(formId, fieldNum, submitId, validImage, invalidImage) {
    Validator.currentSelector = '';
    Validator.currentForm = formId;
    gebid(Validator.currentForm).reset( );
    Validator.fieldNumValidated = 0;
    Validator.fieldNumToValidate = fieldNum;
    Validator.submitId = submitId;
    Validator.validImage = validImage;
    Validator.invalidImage = invalidImage; }

Lots going on here. In the above function expression, an anonymous (nameless) function is defined and then associated with the aforecreated Validator object via an Initialize name - see the "Defining methods" section of the JavaScript 1.5 Core Guide - the association part occurs when Validator.js is imported, but the statements in the function body are not executed until the function is called via the Validator.Initialize( ) command of demo.html's onload event handler.

The function body defines seven custom properties for our custom Validator object:
(1) currentSelector, which will later represent a to-be-validated control object and is initialized to an empty string;
(2) currentForm, which is set to formId (liveForm), the id of the to-be-validated form, and then on the next line is shipped off to the gebid( ) function to get the liveForm form so that it can be reset( ) if necessary;
(3) fieldNumValidated, which will tally the number of liveForm fields that have been filled out correctly and is accordingly initialized to 0;
(4) fieldNumToValidate, which is set to fieldNum (6) and will represent the total number of liveForm fields that must be filled out correctly;
(5) submitId, which is set to submitId (submit), the id of the submit button, and will later be used to un/disable the button;
(6) validImage, which is set to validImage (img/check.gif), the URL path to the check.gif image; and
(7) invalidImage, which is set to invalidImage (img/x.gif), the URL path to the x.gif image.
For these assignments, we could use the keyword this in place of the Validator object reference, i.e.:

this.currentSelector = '';
this.currentForm = formId;

We are finally ready to fill out, and validate, the liveForm form. Beginning at the top, let's say we enter Kris into the "Your first name: *" field and then tab to the "Your last name: *" field. We'll go through the gory details of what happens next in the following entry.


Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)