Spry Conditional Validation

Spry Add comments

Spry blog posts seem a little thin on the ground, so I thought I'd start a series of Spry related posts covering some of the issues that we've come across in the rebuild of the HostelBookers site (yet to be launched).  Spry was the AJAX framework of choice for the project before I arrived at HostelBookers and as I'd had a little experience with it in my last job we decided to carry on with it.  I've since been named "SpryMan/Guy".  Not sure whether to be proud of that or not. Spry seemed to fit nearly all of our AJAX-type needs especially in the data display/filtering/sorting capacity, but it is lacking in some other areas, so we had to draft in jQuery for a nice datepicker and other UI bits and bobs.  I think if I got a chance to start from scratch I'd stick to one framework completely, and I think it would be jQuery (mainly for the size of the community).

So my first example will be on conditional validation.  We have a section of the site that has a little survey. The very first question decides whether you need to answer further questions or not.  If you get the futher questions displayed those fields need to be validated, if they're not, the validation is unnecessary. This will be a generic example, not quite as large as our actual page:

First you'll need to include the required Spry librarys and validation CSS in the <head> for the functionality we're going to use (if you haven't got Spry yet, it's available from Adobe Labs, but the download below includes all the files used in this example). For this example we'll use:

<link rel="stylesheet" type="text/css" href="spry/SpryValidationTextField.css">
<link rel="stylesheet" type="text/css" href="
spry/SpryValidationRadio.css">
<style type="text/css">
        .hide {display:none;}
</style>
<script type="text/javascript" src="spry/SpryUtils.js"></script>
<script type="text/javascript" src="
spry/SpryDOMUtils.js"></script>
<script type="text/javascript" src="
spry/SpryValidationTextField.js"></script>
<script type="text/javascript" src="
spry/SpryValidationRadio.js"></script>

The Spry CSS covers the validation indicators by hiding the messages by default and colouring fields when they meet certain criteria.  The ".hide" class is added to hide the optional questions in our form.  Of the Spry JavaScript, the first two are helper utilities, the second two are for the form input validation. We're only going to validate text fields and radio buttons in this example, but you can add select, textarea and/or checkbox valdiation as required.  I tend to use the minified versions of the JS files.  Packed ones are usually smaller, but the decompression of them can add an overhead.

Our XHTML form will be:

<form name="frmQuestions" id="frmQuestions" action="index.html" method="post">
<div id="valMoreQuestions">
<p>1. Would you like some more questions?</p>
<label for="moreQuestionsYes">
<input type="radio" name="moreQuestions" id="moreQuestionsYes" value="true" />
Yes please.
</label>
<br />
<label for="moreQuestionsNo">
<input type="radio" name="moreQuestions" id="moreQuestionsNo" value="false" />
No thanks.
</label>
<br />
<span class="radioRequiredMsg">Please select</span>
</
div>
 
<
div id="valExtraQuestion1" class="hide optionalQ">
<p>2. Extra question one.</p>
<label for="extraQuestion1">Who is your daddy?</label>
<input type="text" name="extraQuestion1" id="extraQuestion1" />
<br />
<span class="textfieldRequiredMsg">Please enter an answer for question 2.</span>
</
div>

<
div id="valExtraQuestion2" class="hide optionalQ">
<p>3. Extra question two.</p>
<label for="extraQuestion2">And what does he do?</label>
<input type="text" name="extraQuestion2" id="extraQuestion1" />
<br />
<span class="textfieldRequiredMsg">Please enter an answer for question 3.</span>
</
div>
<br /><br />
<input type="submit" name="submitAnswers" id="submitAnswers" value="Submit Answers" />
</form>

The form is pretty basic with a few things to note.  Each question is wrapped in a <div> with an id.  This is so Spry can reference <input> tag it contains and apply the appropriate validation. The <div> tags that wrap the optional questions are given 2 extra classes; "hide", to make sure they're not visible from the offset and "optionalQ" so we can easily select just the optional questions later.  Each question's <div> also includes a validation message within a nested <span> tag.  The class name of this determines which validation error has occured and so which message to display (these can be found in the Spry Documention, or customised with your own class names when constructing the validation object).    The <br />'s are just to make it a little tidier to view.

And finally out custom <script> to make it work:

<script type="text/javascript">
var valMoreQuestions = new Spry.Widget.ValidationRadio("valMoreQuestions", {validateOn:["change"]});
var valExtraQuestion1;
var valExtraQuestion2;
       
Spry.$$("#
valMoreQuestions input").addEventListener("click", toggleAdditonalQuestions, false);
       
function toggleAdditonalQuestions(e) {
if(e.currentTarget.value == "true") {
//loop over all elements with a class of "
optionalQ" and REMOVE the class of "hide"
Spry.$$(".optionalQ").forEach(function(qs){Spry.Utils.removeClassName(qs,"hide");})
//...and set up radio validation...
valExtraQuestion1 = new Spry.Widget.ValidationTextField("valExtraQuestion1", "none", {validateOn:["change"]});
valExtraQuestion2 = new Spry.Widget.ValidationTextField("valExtraQuestion2", "none", {validateOn:["change"]});
} else {
//loop over all elements with a class of "
optionalQ" and ADD a class of "hide"
Spry.$$(".optionalQ").forEach(function(qs){Spry.Utils.addClassName(qs,"hide");})
//destroy all the validation (if they were set up)
if(valExtraQuestion1) {
valExtraQuestion1.reset();
valExtraQuestion1.destroy();
}
if(valExtraQuestion2) {
valExtraQuestion2.reset();
valExtraQuestion2.destroy();
}
}   
}
</script>

So this JavaScript block is where all the magic happens.  First we set up our variables, "valMoreQuestions" can be set up with Spry Radio Validation straight away as it's always displayed. The next 2 are just set up as placeholders to be filled if they need to be shown. 

Next we add event listeners to the 2 radio buttons, so both fire the function "toggleAdditonalQuestions" when clicked. This is where the included SpryDOMUtils comes in very useful. "Spry.$$(CSS Selector)" allows you to select any elements from the DOM from their CSS selectors, so you can be as specific or generic as you need.  In the case of adding the event listeners to the radio buttons we've selected "#valMoreQuestions input", so all <input> tags under an element with the id of "valMoreQuestions".  This powerful little utility makes selecting and manipulating DOM objects a breeze.  In addtion to their selection we use the .addEventListener() method to attach the listener.

Now the event listeners are set up the last part is the function that called when these event are fired, "toggleAdditonalQuestions".  This function first tests to see that the value of the currentTarget of the fired event is true (the value of the radio button clicked).  If it is, we use another DOM selector to get all the elements with a class of "optionalQ".  On this selection of objects we call the forEach() method with fires a function for each element it's found in the selection phase.  Each object is passed to the function as an argument so we can then remove the class of "hide" for each one using the SpryUtils function "Spry.Utils.removeClassName(qs,"hide")" (qs being a single element found in the DOM selector).  This displays the 2 optional questions. We then add the validation to these options.

If the "No thanks" radio option is clicked the reverse happens.  The ".optionalQ" classed elements are selected again and have a class of hide added to them to make them disappear.  We then check if the 2 optional validation variable are set with an if statement (we do this becuase the user may have clicked "No thanks" first and the following functions wouldn't be available. If the variables are defined we use the reset() and destroy() methods on the validation object to remove it.

Spry automatically does the rest of the work to trigger the appropriate validation on clicking the submit button.  We also added the additional "validateOn:["change"]" to all the validation so they will also validation on the change event.

Download the example files. Also the Spry API is an invaluable reference for all the methods and options.

4 responses to “Spry Conditional Validation”

  1. Dav Says:
    Hi,

    Thanks for this !
    I was looking for that kind of stuff.

    It work perfectly since i try with ie 6. ^^
    (Evrything OK with FF)
    It seems that the toggleAdditonalQuestions is not fired by the listner.

    Please mister "SpryMan/Guy" any idea ?

    Thanks from France...

    Dav
  2. Rebecca Says:
    I get an error "currentTarget is null or not an object" when I click on the radio buttons.
  3. Ken Says:
    IE7 sends the same error and does not work; "currentTarget is null or not an object".
  4. Jamie Says:
    cant get select to work

    Any ideas

    <div id="spryselect1">
    <label>How did you hear abour us?
    <select name="hear_about_us" id="hear_about_us">
    <option value="-1" selected="selected">--Please Select--</option>
    <option value="Internet">Internet</option>
    <option value="TV commercial">Television Commercial</option>
    <option value="TV show">Television Show</option>
    <option value="Yellow Pages">Yellow Pages</option>
    <option value="Magazine / Paper">Magazine / Paper</option>
    <option value="Referred">Referred</option>
    <option value="Existing Client">Existing Client</option>
    <option value="Other">Other</option>
    </select>
    </label>
    <span class="selectInvalidMsg">Please select a valid item.</span><span class="selectRequiredMsg">Please select an item.</span></div>


    <div id="sprytextfield1" class="HearAbout">
    <label>Which website?
    <input type="text" name="internet" id="internet" />
    </label>
    <span class="textfieldRequiredMsg">A value is required.</span></div>


    <p>&nbsp;</p>


    <div id="sprytextfield2" class="hide HearAbout">
    <label>Which TV commercial
    <input type="text" name="tv_commercial" id="tv_commercial" />
    </label>
    <span class="textfieldRequiredMsg">A value is required.</span></div>





    var spryselect1 = new Spry.Widget.ValidationSelect("spryselect1", {invalidValue:"-1", validateOn:["blur", "change"]});
    var sprytextfield1;
    var sprytextfield2;

    Spry.$$("#spryselect1 input").addEventListener("click", toggleHearAboutUs, false);

    function toggleHearAboutUs(sel) {

    if(sel.currentTarget.value == "Internet") {
    //loop over all elements with a class of "optionalQ" and REMOVE the class of "hide"
    Spry.$$(".HearAbout").forEach(function(rh){Spry.Utils.removeClassName(rh,"hide");})
    //...and set up radio validation...
    sprytextfield1 = new Spry.Widget.ValidationTextField("sprytextfield1", "none", {validateOn:["blur", "change"]});
    sprytextfield2 = new Spry.Widget.ValidationTextField("sprytextfield2", "none", {validateOn:["blur", "change"]});
    } else {
    //loop over all elements with a class of "optionalQ" and ADD a class of "hide"
    Spry.$$(".HearAbout").forEach(function(rh){Spry.Utils.addClassName(rh,"hide");})
    //destroy all the validation (if they were set up)
    if(sprytextfield1) {
    sprytextfield1.reset();
    sprytextfield1.destroy();
    }
    if(sprytextfield2) {
    sprytextfield2.reset();
    sprytextfield2.destroy();
    }
    }

Leave a Reply





Powered by Mango Blog. Design and Icons by N.Design Studio