In this article I will try to explain how you can dynamically change a TextBox field validation
based on a value selected in a DropDown (select) field. Additionally we will create and use a custom validation.
This article will actually make you understand how things work and it only requires some basic
knowledge of Joomla, ChronoForms, php, javascript and the LiveValidation class.
Please note this is a tested and working solution. However I'm not a javascript guru. So undoubtedly
the javascript code provided can be optimized.
There are 3 major problems we need to solve to get this working.
1. How do we use the livevalidation object(s) (we don't know how they are named in Chronoforms) ?
2. How can we get the livevalidation "remove" method working (believe me you WILL run into this challenge) ?
3. How to create a custom validation ?
Once we overcome these 3 barriers, dynamically changing (custom) field validation is a piece of cake.
To give you an idea of how the livevalidation works we'll first look at a simplified javascript example.
//STEP 1: Let's define a livevalidation object on a field called zipcode.
var name = new LiveValidation('zipcode');
//STEP 2: And since it is a required field we add a Presence validation (rule) to it:
name.add( Validate.Presence, {failureMessage: 'Required !'});
//STEP 3: We also want to add a (custom) Format validation (rule)(Dutch zipcode ->1000AA or 1000 AA):
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
name.add( Validate.Format, {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_zipcode_nl});
That's it. We now have a (custom) validated zipcode field which requires a value and the format of the
value should be 1000AA (or 1000 AA). So this actually solves/answers problem no 3.
So far so good.
--//--
Now suppose there is another field called Country. This is the dropdown (select) field and it
offers 4 possible values; --Select--, Netherlands, Belgium and Germany. The idea is to change the zipcode
validation based on the value selected in the Country dropdown (select) field.
Here is where the magic starts.
Whenever a different Country is selected in the Country dropdown (select) field the Format validation
(rule) of the zipcode field (STEP 3) should change to the right format for the selected country.
We have already seen that the Dutch zipcode format is 4 numbers followed by a space (or not) and then 2
alphanumeric chars.
The German zipcode format is 5 numbers.
var msg_invalid_zipcode_de = 'Invalid German zipcode';
name.add( Validate.Format, {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_zipcode_de});
The Belgian zipcode format is 4 numbers.
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
name.add( Validate.Format, {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_zipcode_be});
So STEP 3 involves these 3 variants for adding Format validation.
Now how are we going to switch from one Format validation (rule) to the other ?
Here is where the livevalidation remove method comes into the picture.
Suppose we have Dutch zipcode validation active and we select Germany in the Country field.
We then need to remove the current Dutch zipcode Format validation (rule) and finally add the German one.
You can remove a validation (rule) from a livevalidation object by simply using the same arguments as when
adding it.
name.remove( Validate.Format, {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_zipcode_nl});
name.add( Validate.Format, {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_zipcode_de});
However when you try this you will run into the issue that the Dutch Format validation (rule) is not removed.
In other words the remove is not working. Why not ?
Basically this issue is caused by the second (parameters object) argument of the add and remove methods.
In order for the remove to work, add and remove need to use the same parameters object argument (not an
identical other object, but exactly the same instance of that object !).
So to resolve this issue we need to (globally) define one parameters object for every country and use it
as the second argument in the add and remove methods.
The code of our example now changes to this:
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
var msg_invalid_zipcode_de = 'Invalid German zipcode';
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
var params_nl = {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_postcode_nl};
var params_de = {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_postcode_de};
var params_be = {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_postcode_be};
//STEP 1: Let's define a livevalidation object on a field called zipcode.
var name = new LiveValidation('zipcode');
//STEP 2: And since it is a required field we add a Presence validation (rule) to it:
name.add( Validate.Presence, {failureMessage: 'Required !'});
//STEP 3: We also want to add a (custom) Format validation (rule)(Dutch zipcode ->1000AA or 1000 AA):
name.add( Validate.Format, params_nl);
Now we can remove a validation by simply using the same arguments as when adding it.
name.remove( Validate.Format, params_nl);
name.add( Validate.Format, params_de);
So this basically solves problem no 2 as defined at the beginning of this article.
--//--
Let's take a look at problem no 1.
We know the ChronoForms (3.2) jsvalidation2.js file is responsible for creating livevalidation objects for
every field that needs to be validated in a form. But how are those objects named and how can we refer
to them once they are created ?
The answer is both in the header of a page containing a validation enabled ChronoForms form as well as in
the jsvalidation2.js file.
The header of a page containing a validation enabled ChronoForms form will show the following piece of
javascript:
The setValidation() function defined in the jsvalidation2.js file creates and stores every livevalidation
object in an array called fieldsarray !
So all you need to know is which livevalidation object is stored where in the array.
Keep in mind the setValidation() function defined in the jsvalidation2.js script first creates all
livevalidation objects for field type text, password, file, checkbox and radio. Then it moves on to
field type select. And finally the textarea field type are processed.
The fieldsarray array will hold all livevalidation objects in the specified order.
Once you have identified where the livevalidation object is stored in the array you can easily refer to it.
In our example we only have 3 form elements. A DropDown (select) field named country, a TextBox field
named zipcode and a Button.
So the zipcode field livevalidation object will be in position 0 of the fieldsarray array.
The code of our example now changes to this:
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
var msg_invalid_zipcode_de = 'Invalid German zipcode';
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
var params_nl = {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_postcode_nl};
var params_de = {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_postcode_de};
var params_be = {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_postcode_be};
name = fieldsarray[0];
//STEP 3: We also want to add a (custom) Format validation (rule)(Dutch zipcode ->1000AA or 1000 AA):
name.add( Validate.Format, params_nl);
As you can see I've removed STEP 1 and 2 since the setValidation() function defined in the jsvalidation2.js
script will take care of creating the livevalidation object(s) in our Chronoforms form and adding the
Required validation to it. We only need to concern ourselves with the custom validation for the zipcode field.
The complete javascript code that needs to be copy/pasted into the Form JavaScript field under the
Form Code tab of a form looks like this (Don't be surprised to see a small piece of php code as well):
And let's not forget the Form HTML that goes with it:
In a future update to this article I will explain how to deal with the situation when
no country (--Select--) is selected. So this gives you some time to figure out a solution on your own.
One hint. Use the LiveValidation enable/disable methods to enable/disable the zipcode
field validation.
Until then any suggestions, remarks, corrections or improvements related to this article are welcome.
PolderGuy
based on a value selected in a DropDown (select) field. Additionally we will create and use a custom validation.
This article will actually make you understand how things work and it only requires some basic
knowledge of Joomla, ChronoForms, php, javascript and the LiveValidation class.
Please note this is a tested and working solution. However I'm not a javascript guru. So undoubtedly
the javascript code provided can be optimized.
There are 3 major problems we need to solve to get this working.
1. How do we use the livevalidation object(s) (we don't know how they are named in Chronoforms) ?
2. How can we get the livevalidation "remove" method working (believe me you WILL run into this challenge) ?
3. How to create a custom validation ?
Once we overcome these 3 barriers, dynamically changing (custom) field validation is a piece of cake.
To give you an idea of how the livevalidation works we'll first look at a simplified javascript example.
//STEP 1: Let's define a livevalidation object on a field called zipcode.
var name = new LiveValidation('zipcode');
//STEP 2: And since it is a required field we add a Presence validation (rule) to it:
name.add( Validate.Presence, {failureMessage: 'Required !'});
//STEP 3: We also want to add a (custom) Format validation (rule)(Dutch zipcode ->1000AA or 1000 AA):
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
name.add( Validate.Format, {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_zipcode_nl});
That's it. We now have a (custom) validated zipcode field which requires a value and the format of the
value should be 1000AA (or 1000 AA). So this actually solves/answers problem no 3.
So far so good.
--//--
Now suppose there is another field called Country. This is the dropdown (select) field and it
offers 4 possible values; --Select--, Netherlands, Belgium and Germany. The idea is to change the zipcode
validation based on the value selected in the Country dropdown (select) field.
Here is where the magic starts.
Whenever a different Country is selected in the Country dropdown (select) field the Format validation
(rule) of the zipcode field (STEP 3) should change to the right format for the selected country.
We have already seen that the Dutch zipcode format is 4 numbers followed by a space (or not) and then 2
alphanumeric chars.
The German zipcode format is 5 numbers.
var msg_invalid_zipcode_de = 'Invalid German zipcode';
name.add( Validate.Format, {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_zipcode_de});
The Belgian zipcode format is 4 numbers.
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
name.add( Validate.Format, {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_zipcode_be});
So STEP 3 involves these 3 variants for adding Format validation.
Now how are we going to switch from one Format validation (rule) to the other ?
Here is where the livevalidation remove method comes into the picture.
Suppose we have Dutch zipcode validation active and we select Germany in the Country field.
We then need to remove the current Dutch zipcode Format validation (rule) and finally add the German one.
You can remove a validation (rule) from a livevalidation object by simply using the same arguments as when
adding it.
name.remove( Validate.Format, {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_zipcode_nl});
name.add( Validate.Format, {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_zipcode_de});
However when you try this you will run into the issue that the Dutch Format validation (rule) is not removed.
In other words the remove is not working. Why not ?
Basically this issue is caused by the second (parameters object) argument of the add and remove methods.
In order for the remove to work, add and remove need to use the same parameters object argument (not an
identical other object, but exactly the same instance of that object !).
So to resolve this issue we need to (globally) define one parameters object for every country and use it
as the second argument in the add and remove methods.
The code of our example now changes to this:
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
var msg_invalid_zipcode_de = 'Invalid German zipcode';
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
var params_nl = {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_postcode_nl};
var params_de = {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_postcode_de};
var params_be = {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_postcode_be};
//STEP 1: Let's define a livevalidation object on a field called zipcode.
var name = new LiveValidation('zipcode');
//STEP 2: And since it is a required field we add a Presence validation (rule) to it:
name.add( Validate.Presence, {failureMessage: 'Required !'});
//STEP 3: We also want to add a (custom) Format validation (rule)(Dutch zipcode ->1000AA or 1000 AA):
name.add( Validate.Format, params_nl);
Now we can remove a validation by simply using the same arguments as when adding it.
name.remove( Validate.Format, params_nl);
name.add( Validate.Format, params_de);
So this basically solves problem no 2 as defined at the beginning of this article.
--//--
Let's take a look at problem no 1.
We know the ChronoForms (3.2) jsvalidation2.js file is responsible for creating livevalidation objects for
every field that needs to be validated in a form. But how are those objects named and how can we refer
to them once they are created ?
The answer is both in the header of a page containing a validation enabled ChronoForms form as well as in
the jsvalidation2.js file.
The header of a page containing a validation enabled ChronoForms form will show the following piece of
javascript:
var fieldsarray = new Array();
var fieldsarray_count = 0;window.addEvent('load', function() {
elementExtend();setValidation("Form_name", 1, 0, 0);});
The setValidation() function defined in the jsvalidation2.js file creates and stores every livevalidation
object in an array called fieldsarray !
So all you need to know is which livevalidation object is stored where in the array.
Keep in mind the setValidation() function defined in the jsvalidation2.js script first creates all
livevalidation objects for field type text, password, file, checkbox and radio. Then it moves on to
field type select. And finally the textarea field type are processed.
The fieldsarray array will hold all livevalidation objects in the specified order.
Once you have identified where the livevalidation object is stored in the array you can easily refer to it.
In our example we only have 3 form elements. A DropDown (select) field named country, a TextBox field
named zipcode and a Button.
So the zipcode field livevalidation object will be in position 0 of the fieldsarray array.
The code of our example now changes to this:
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
var msg_invalid_zipcode_de = 'Invalid German zipcode';
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
var params_nl = {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_postcode_nl};
var params_de = {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_postcode_de};
var params_be = {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_postcode_be};
name = fieldsarray[0];
//STEP 3: We also want to add a (custom) Format validation (rule)(Dutch zipcode ->1000AA or 1000 AA):
name.add( Validate.Format, params_nl);
As you can see I've removed STEP 1 and 2 since the setValidation() function defined in the jsvalidation2.js
script will take care of creating the livevalidation object(s) in our Chronoforms form and adding the
Required validation to it. We only need to concern ourselves with the custom validation for the zipcode field.
The complete javascript code that needs to be copy/pasted into the Form JavaScript field under the
Form Code tab of a form looks like this (Don't be surprised to see a small piece of php code as well):
<?php
jimport('joomla.environment.browser');
$browser = JBrowser::getInstance();
if ( $browser->getBrowser() == 'msie' ) {
$loader = 'load';
}
else {
$loader = 'domready';
}
echo "window.addEvent('$loader', function() {"."\n";
?>
var msg_invalid_zipcode_nl = 'Invalid Dutch zipcode';
var msg_invalid_zipcode_de = 'Invalid German zipcode';
var msg_invalid_zipcode_be = 'Invalid Belgian zipcode';
var params_nl = {pattern: /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/, failureMessage: msg_invalid_postcode_nl};
var params_de = {pattern: /^[0-9]{5}$/i, failureMessage: msg_invalid_postcode_de};
var params_be = {pattern: /^[0-9]{4}$/i, failureMessage: msg_invalid_postcode_be};
el_cntry = $('country');
el_zcode = $('zipcode');
var lv_zipcode = fieldsarray[0];
lv_zipcode.add( Validate.Format, params_nl);
var oldValue = el_cntry.options[el_cntry.selectedIndex].value;
el_cntry.addEvent('change', changeHandler);
function changeHandler(event) {
switch(oldValue){
case 'NL':
lv_zipcode.remove(Validate.Format, params_nl);
break;
case 'DE':
lv_zipcode.remove(Validate.Format, params_de);
break;
case 'BE':
lv_zipcode.remove(Validate.Format, params_be);
break;
}
switch(this.value){
case 'NL':
lv_zipcode.add(Validate.Format, params_nl);
el_zcode.maxLength = 7;
break;
case 'DE':
lv_zipcode.add(Validate.Format, params_de);
el_zcode.maxLength = 5;
break;
case 'BE':
lv_zipcode.add(Validate.Format, params_be);
el_zcode.maxLength = 4;
break;
}
oldValue = this.value;
}
});
And let's not forget the Form HTML that goes with it:
<div class="form_item">
<div class="form_element cf_dropdown">
<label class="cf_label" style="width: 60px;">Country</label>
<select class="cf_inputbox validate-selection" style="width: 100px;" size="1" title="Select a country" id="country" name="ncountry">
<option value="">--Select--</option>
<option value="BE">Belgium</option>
<option value="DE">Germany</option>
<option value="NL" selected="">Netherlands</option>
</select>
</div>
<div class="cfclear"> </div>
</div>
<div class="form_item">
<div class="form_element cf_textbox">
<label class="cf_label" style="width: 60px;">Zipcode</label>
<input class="cf_inputbox required" style="width: 60px;" maxlength="7" size="7" title="" id="zipcode" name="nzipcode" type="text" />
</div>
<div class="cfclear"> </div><br />
</div>
<div class="form_item">
<div class="form_element cf_button">
<input value="Submit" name="button_1" type="submit" />
</div>
<div class="cfclear"> </div>
</div>
In a future update to this article I will explain how to deal with the situation when
no country (--Select--) is selected. So this gives you some time to figure out a solution on your own.
One hint. Use the LiveValidation enable/disable methods to enable/disable the zipcode
field validation.
Until then any suggestions, remarks, corrections or improvements related to this article are welcome.
PolderGuy