Really easy field validation with Prototype

Saturday, January 6, 2007

I wanted a robust javascript validation library that was simple to implement and didn't require me do any extra work other than creating the form. My favourite idea for a method of doing this is to utilise the field elements' class attribute to indicate what sort of field it is and hence any validation requirements. There are a few javascript libraries that implement that idea like wForms, but, since I'm currently hell-bent on re-writing all my javascript using Prototype, I thought I'd see how difficult or easy it would be to roll my own. Turns out that this is just the sort of thing that is easy with Prototype. Here's what I came up with.

Do not be alarmed! The library has moved here.

100 Comments

#1
On the April 28, 2006, Adrian wrote:

Does the script check to see if a validated fields is within a hidden element and therefore not trigger?

A

#2
On the April 28, 2006, Andrew Tetlaw wrote:

"So here it is in it's first usable, albeit basic, form."

Not yet ;)

#3
On the April 28, 2006, Andrew Tetlaw wrote:

It does now!

#4
On the May 1, 2006, Matthias wrote:

<a href="http://www.matsblog.com/stories/1897119/">realy great work!</a> (because i can't use trackback here :)

#5
On the May 1, 2006, Mike Rumble wrote:

Great script.

By adding a couple of lines to the script I've added 'blur' capabilities to this script, so that the validation can also be run when a field loses focus.

I added the following few lines of code to the Validation.initialize method:

Form.getElements(this.form).each(function(input) {
Event.observe(input, 'blur', function(ev) { $V(Event.element(ev).id) });
});

Seems to work a treat!

#6
On the May 1, 2006, Andrew Tetlaw wrote:

Thanks Mike, looks great! I might add it and make it optional.

#7
On the May 2, 2006, rosemary wrote:

You rock!

#8
On the May 3, 2006, Benoit wrote:

Great. Does it work with other fields ?(SELECT, TEXTAREA...)

#9
On the May 3, 2006, Andrew Tetlaw wrote:

Hi Benoit (8), it simply tests the value returned by the prototype $F(element) function. So the simple answer is yes, it does all those.

#10
On the May 6, 2006, German wrote:

It's a pitty that this very same form, doesn't use such a nice script.
Come on! You can show it off a little bit!

#11
On the May 10, 2006, tom wrote:

when you have time, would you please add a basic US/Canadian phone number validation for format 123-456-7890??

beyond this, thank you very much for working on this, standard validations like this should be included in all the good javascript libraries!!

thank you, :) tom

#12
On the May 10, 2006, Brice Burgess wrote:

I'm into it.

One day I'd like to tie this into SmartyValidator (for those of us still coding in PHP w/ SMARTY templates). Until then; this is going in the bookmarks.

Good work

~ Brice

#13
On the May 10, 2006, Joe Black wrote:

One thing that is seriously lacking is server side validation, that's kinda the whole point of AJAX form validation isnt it? To avoid page refreshes with XMLHTTPRequest. Other than that, great implementation!

#14
On the May 10, 2006, Huy Do wrote:

have you heard of TMT validator. It is a much cleaner way of dealing with validation. google it.

#15
On the May 10, 2006, Jonathan Wise wrote:

Hmm... looks very similar to my solution.
http://software.jonandnic.com/jsObjects
Check out jsUI-Textbox, which reads extended attributes of form-field elements to validate types...

#16
On the May 10, 2006, Colemaco wrote:

I like it.

#17
On the May 10, 2006, Marty wrote:

Very cool. I've created something very similar, but instead of validation it does keypress masking (ie: class="mask-alphaNumeric")

One thing you might consider, rather than using a constructor like "new Validation('form-id')", you could simply add a className to the form itself, ala [form class="Validate" ...]

Or, i suppose it would be possible to skip that step altogether, and just parse every form for validate-* classNames, and invoke the constructor as required.

Neat stuff!

#18
On the May 10, 2006, Analgesia wrote:

look great.
just spotted a small typo:
dd/mm/yyy should be dd/mm/yyyy

#19
On the May 10, 2006, Supernerd wrote:

This is really nice. I am going to write support for this into Zoop Framework, a PHP framework that already has excellent validation, but could use a cleaner javascript implementation. I will let you know when it is done. To work with Zoop we would need a few more validation types which I can add and share back. 

#20
On the May 10, 2006, foo wrote:

Prototype.js - or the way you are using it - leaks memory in Firefox.

Install this:
https://addons.mozilla.org/firefox/2490/

Run dexagogo's code, and see for yourself

#21
On the May 10, 2006, an0n wrote:

Prototype.js - or your use of it - leaks memory in Firefox. Install this:

https://addons.mozilla.org/firefox/2490/

then run this dexagogo demo and see for yourself!

#22
On the May 11, 2006, Daniel Schierbeck wrote:

The e-mail validator doesn't work properly; it doesn't support international addresses[EDITED OUT] That's a valid e-mail address, but it doesn't work in the demo.

#23
On the May 11, 2006, klevo wrote:

Great article. Thanks.

I am trying to impement this technique but can not get it to work with IE. My example: http://klevo.yweb.sk/forms/1/

Any suggestions?

#24
On the May 11, 2006, Trejkaz wrote:

Problem is, I already have validations defined in my Rails models, and I Don't want to Repeat Myself by having validation code in the views.

10 points to the first developer who makes this work *without* explicitly adding extra code to the views.

#25
On the May 11, 2006, Andrew Tetlaw wrote:

Arrrrg, I got dugg.

Anyways, Joe (13), yeah it's nothing to do with AJAX, just a little javascript validation library. JS validation is good because it saves a trip to the server for basic problems.

But,Server side validation is a must for many reasons, not the least of which is security. If the user-agent does not execute javascript, your only fall back is server-side validation.

JS validation is a nice little extra and as such the easier you can implement it the better.

#26
On the May 11, 2006, Andrew Tetlaw wrote:

Thanks for the typo warning Analdesia (18)!

Brice (12) and Supernerd (19) glad you can find it useful. Let me know how you get on.

an0n (21), thanks for the heads up.

#27
On the May 11, 2006, Andrew Tetlaw wrote:

Klevo (23) probably something to do with window.onload=function() {
Nifty("div#form1", "big");
}
use the prototype Event.observe for that too and see how you go.

#28
On the May 11, 2006, Andrew Tetlaw wrote:

Sorry, Daniel Schierbeck (22), the email address borked the page... yeah yeah I know... It'll be fixed.

#29
On the May 11, 2006, Alex wrote:

Why are you using the class attribute for specifying validation requirements? That means you won't be able to use the class attribute for styling text boxes or just the text inside. The alt attribute would be better as browsers don't do anything with it but is accessible. 

Have you ever heard of fValidate? A greate validation kit but not supported any more. It would be nice if some Javascript guru would pick up where the original programmer left off.

#30
On the May 11, 2006, Andrew Tetlaw wrote:

Hi Alex (29), what's stopping you from using it for both? I use the class 'required' for validation but also in the CSS in the demo. That's what gives required fields the blue border. You can also add your own CSS class name to the class attribute and the validation library will ignore it. for example: 

class="required big-red-box"

#31
On the May 11, 2006, Mike wrote:

Nice script. How about functionality for "at least X characters" or "no more than X characters" or combination of both? Addition of phone number validation would be cool too!

Thx,
Mike

#32
On the May 11, 2006, Glenn wrote:

If I submit '-1' for the donation amount in the demo it passes the validation. Does that mean you owe me money?  ;-)

#33
On the May 11, 2006, Andrew Tetlaw wrote:

Glann (32), yes it does! Congratulations! To claim your nomintated dollar amount please post your bank account details and home address!

#34
On the May 11, 2006, Francis wrote:

i seldom post my forms using the Submit button
but calling javascript to do 
document.myForm.submit();

doesnt seem to capture the event when submitted this way

#35
On the May 11, 2006, Mauricio wrote:

I was trying wForms today! You've made a really great work here too!!!

I would like to know if there is an easy way to make the values of elements in an 'display:none' don't be submited.

#36
On the May 11, 2006, Andrew Tetlaw wrote:

Francis (34), that's because the validation library adds an event listener to the onsubmit event and it is a generally known that when calling form.submit() the browsers do not fire the onsubmit event. What you generally have to do is write a custom form submit function which fires the onsubmit and then submit functions manually.

For example: http://www.javascript-coder.com/javascript-form/javascript-form-submit.phtml

#37
On the May 11, 2006, Francis wrote:

oh thanks

this bit of code did the job 

<input type="submit" name="fakeSubmitButton" style="display: none"/>

instead of calling document.forms['form name'].submit(); call
document.forms['form name'].fakeSubmitButton.click();

#38
On the May 11, 2006, Joe Black wrote:

Arrrrg, I got dugg.

Anyways, Joe (13), yeah it's nothing to do with AJAX, just a little javascript validation library. JS validation is good because it saves a trip to the server for basic problems.

But,Server side validation is a must for many reasons, not the least of which is security. If the user-agent does not execute javascript, your only fall back is server-side validation.

JS validation is a nice little extra and as such the easier you can implement it the better.

==============================================
Right, but without server side validation, wouldn't this just be an enhanced alert eyecandy? Server side validation will really improve this already great implementation :)



#39
On the May 11, 2006, Joe Black wrote:

Forgot to mention, it can be client side for basic validations still, only those require server trips will post a request. I believe this is how wForm works too.

#40
On the May 11, 2006, Dom G wrote:

great script! But Im using it on a file upload....

<input type="file" name="imageupload" id="imageupload" value="" class="required" />


... and it returns the validation failed fine but when a file is attached still returns validation failed... Any ideas?

Thanks

#41
On the May 12, 2006, Sidney wrote:

I like it. But it had one drawback for me: The error messages are 'hard-coded' in the JS file, but I'd like them in my view (for example, if you're going multi-language).
So I hacked a bit, and Now you can (but you don't need to) add a element to your HTML code with the proper id (the same the automatically generated element uses), hide it per CSS and if the validation test failed, it will be displayed. And it falls back to generation if you don't have an element.
---
Code:
[before if(typeof Effect == 'undefined') {]
var advice = $(id);
if(advice == undefined)
{
advice = document.createElement('div');
this.parentNode.insertBefore(advice, this.nextSibling);
advice.className = 'validation-advice';
advice.id = id;
advice.appendChild(document.createTextNode(v.error));
};

#42
On the May 12, 2006, Andrew Tetlaw wrote:

Dom G (40), the script only tests the value returned from the $F function in Prototype. Looking at it now, it does not support input elements of type file. It'll return blank every time.

Sidney (41), that's a great idea!

#43
On the May 14, 2006, Derek wrote:

I was trying to validate a name field and it always failed regardless of whether I used alpha or alphanum.

The name was: Scott O'Neil

The apostrophe was making it fail, but so was the space between the first and last names.
I guess I'll just mark it as 'required'.
Anyway, thought it was something that should be in your comments.

Keep up the awesome work :)

#44
On the May 15, 2006, Andrew Tetlaw wrote:

Thanks Derek (43), I'll look into it. I have a healthy to-do list now, after all these comments!

#45
On the May 15, 2006, Phill Howson wrote:

This is great work!

I'm using prototype and fValidate in my projects - whilst fValidate is great, the code is a bit bulky, however there are some things it can do over and above this - 

1) checkbox / radio validation - validates single/multiple selections and displays errors at the end of the group

2) 'equalto' as a validation type - great for checking for email address typo's

Whilst evaluating this code, I wrote a couple of extra validaton types that might be useful to others:

['validate-ukpost', 'Please enter a UK postcode.', function(v) {
return Validation.get('IsEmpty').test(v) ||  /^[A-Za-z]{1,2}[\d]{1,2}([A-Za-z])?\s?[\d][A-Za-z]{2}$/.test(v)
}],
['validate-ukphone', 'Please enter a UK postcode.', function(v) {
// pattern from http://www.regexlib.com/REDetails.aspx?regexp_id=589
return Validation.get('IsEmpty').test(v) ||  /^(((\+44\s?\d{4}|\(?0\d{4}\)?)(\s?\d{3}\s?\d{3}|\s?\d{5}))|((\+44\s?\d{3}|\(?0\d{3}\)?)(\s?\d{3}\s?\d{4}|\s?\d{3}\s?\d{3}))|((\+44\s?\d{2}|\(?0\d{2}\)?)(\s?\d{4}\s?\d{4})|\s?\d{3}\s?\d{4}))(\s?\#(\d{4}|\d{3}))?$/.test(v)
}]

#46
On the May 15, 2006, Andrew Tetlaw wrote:

Thanks Phil (45), that's awsome. Points 1 and 2 are great and should be added, I agree.

Thanks for your validator patterns. One point my preference is to make validator keys have the country codes last like: 'validate-phone-uk'. I just like the neatness of a bunch of 'validate-phone-XX' patterns for internationalisation.

#47
On the May 16, 2006, John wrote:

Very nice script and came in extremely handy, thanks!

It would be really great if the library did a focus() on the first field that fails. The reason being that on very long forms, the user is left with no indication of what happened if a field at the top of page fails, and they pressed submit at the bottom.

#48
On the May 18, 2006, Grant wrote:

Awesome script! I could see myself using it for all the forms I build.

One caveat I did notice is with <select> boxes. Consider the following <select> box:

<select id="test" name="test" class="required">
<option value="">Please Select..</option>
<option value="val1">Value 1</option>
<option value="val2">Value 2</option>
</select>

If submitted with the blank value, $F() will for some reason return the value "Please Select..". a bug? feature?  who knows.

As a workaround, I created my own validation for select boxes, "validate-select".


#49
On the May 18, 2006, Daniel wrote:

First off, brilliant idea that works very effectively. I would like to be able to submit the form via AJAX, but that requires me to intercept the submit request, but that then stops the validation occuring. Any idea how I can get it so that on submit it does:
1) Validation
2) Custom function
3) Cancel submission event

I suppose this is really a prototype question, how to add an additional function to an event.

#50
On the May 18, 2006, Andrew Tetlaw wrote:

John (43), You wish has been granted!
Grant (44), great! That's exactly how I intended the library to be used.
Daniel (45), Event.observe() allows you to do that.

#51
On the May 18, 2006, yingfeng wrote:

Good,but it is difficult to show i18n error message in this schema,because the error message is included in the javascript file,if the implementation can separate the message text from the javascript file,it will be better,i think

#52
On the May 18, 2006, Grant wrote:

..And if anyone is wondering what the validate-select function looks like:

Validation.add('validate-select', 'This is a required field.', function(v) {
return ((v != "none") && (v != null) && (v.length != 0));
});

#53
On the May 19, 2006, yingfeng wrote:

sorry,i am wrong,i18n can be easily got..

#54
On the May 20, 2006, Chunk wrote:

Hi. This is really really great work. Just yesterday we were discussing building something similar to use with random projects here at work. You've saved a lot of headache and done it about 23 times cleaner than I could have. 

Thank you so much.

#55
On the May 20, 2006, daryn wrote:

How do I call some more javascript after validation? (like if I want to submit the form via AJAX if it's valid)

It would be nice if you could call a static Validation.validateForm('form-id') so that you could call it inside of your own onsubmit, from your example it looks like i'd have to call Valiation.validate('field-id') for each field.. 

Of course, I didn't look at the code, so slap me if I'm wrong!!! :)

#56
On the May 20, 2006, Andrew Tetlaw wrote:

Hi daryn, if you assign the object instance to a variable you can call the validate function manually.

i.e. var valid = new Validation('form');

then call If(valid.validate()) {} whenever you like.

#57
On the May 23, 2006, Rob McDonagh wrote:

Nicely done, Andrew.  

One minor tip on your numeric validation (validate-number) on the demo page - it accepts the space character as a valid number. The Javascript isNaN function is to blame; it thinks the space character is a number - not sure why.

#58
On the May 23, 2006, Sam wrote:

Hey,

Great script, i just need to know a couple of things though, where abouts does it tell it to stop and carry on submitting them form? As i'd like to modify it so when you submit it, it uses  
returns something like "Form Submitted" or something like that?

#59
On the May 23, 2006, Sam Again wrote:

Basically the question i asked should be, what does your script use to stop and start the form submission?

#60
On the May 23, 2006, Andrew Tetlaw wrote:

Hi Rob, thanks for the isNaN tip.

Hi Sam Again, It uses the Event.observe() function from Prototype to add an event listener to the form's onsubmit event. Then, if validation fails, it cancels the event.

#61
On the May 23, 2006, ReynierPM wrote:

This is a great library, but I have two questions:
1) It's possible put two elements for a class? e.g: class="required validate-email"
2) How I can validate if two fields have the same content? Use in form for password validation

Regards

#62
On the May 23, 2006, Andrew Tetlaw wrote:

Hi ReynierPM, 1) yep, see the demo, 2) You'll need to write your own valildator.

#63
On the May 23, 2006, wouaren wrote:

Hi, very very nice, worked on it all the morning at work.
I'm from france so we use éïù, - in names etc...
I can't find a good validation for this cases, how can i modify validate-alpha regex ([a-zA-Z]+$) to add support of accentued letters and "-" in names for form (eg: what's your name : ? Vincent voyé-georges (yes it can happend)

I think people outside france will be very happy too because we're not the ones to use accentued letters AND especially "-" wich you must use too in your names.

THANK YOU

#64
On the May 24, 2006, Sam wrote:

Hey,

Its sam again from (58) :P
Ok i understand where if validation fails it uses Event.stop(ev);.

I see how to set validation rules, is there anyway to get it, so when they submit it checks a mysql database for an existing username/email or whatever and then returns, "User already exists" etc? I am fluent in php, im presuming that would help :P Please contact me on msn/email, i would love if you could help me :D samcleaver.beaver [a':'t] gmail.com. 

#65
On the May 24, 2006, Phill Howson wrote:

Hi Andrew, relating to my earlier post (45) I've had a go at writing a validator for "equalto".

I have a strong suspicion there is a better way to approach this problem, but this sort-of works for me.

Hopefully my attempt can inspire some better programmers out there than me ;-)

['validate-equalto', 'Please ensure these values are equal', function(v) {
// won't work properly with {immediate : true}
var elmEqualto = document.getElementsByClassName('validate-equalto');
return ($F(elmEqualto[0].id) != $F(elmEqualto[1].id)) ? false:true;
}]

Keep up the great work.
Phill

#66
On the May 25, 2006, nate wrote:

Great stuff....

I have a prob though. It seems that I have to add an "id" element to every input field I have. Is there a reason why? Can you make it so it doesn't have to do that?

#67
On the May 25, 2006, Issac wrote:

Any particular reason not to extend the test callback from (v) to (v,elem) [by switching !v.test($F(this)) to !v.test($F(this),this)) in Validation.test]?

It could be useful for allowing more application-specific validation rules which want to look at, say, the element id, or whatnot...

#68
On the May 25, 2006, Andrew Tetlaw wrote:

Hi wouaren, yep internationalisation is something I'd like to tackle. But in regular expressions it looks like the only option is to use unicode escapes. For example [\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff]
is the set of all the Latin-1 character codes that you mention in your comment. I used a set generator from here:
http://www.codeproject.com/dotnet/UnicodeCharCatHelper.asp

very handy tool!

#69
On the May 25, 2006, Andrew Tetlaw wrote:

Sam, AJAX validation is something I'll tackle soon.

Thanks Phil! I'm working on making validaiton like that easier.

Nate, yep I can make it so it doesn't have to do that.

Issac, look for the next release.

#70
On the May 26, 2006, Sam wrote:

Andrew your great.. :D

#71
On the May 28, 2006, winner wrote:

I used it as below:
[snip]then,i find something which may be improved on:
1. if i press submit button directly,the required tooltips while appear below <input type="checkbox">,not appear below <textarea>.
it seem the framework don't support <textarea>.

2.if i fill <textarea> and <checkbox>,then press submit button,the radio input check will work,but it can't show required tooltips.

3.i suggest it may be better if your framework can use form item's title attribute as required tooltips .because i'm a chinese,and required work on Chinese tooltips.
allthougn i can modify your framework source code by my own.

however,thanks for create this wonderful frame,wish it be great better,and you !

#72
On the May 30, 2006, Marcus Bointon wrote:

Sorry, It's not my day. I hope you can delete that last one:

['validate-url', 'Please enter a valid URL.', function (v) {
return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\//i.test(v)}]

#73
On the May 31, 2006, xav wrote:

Hello,

Thank you for your work. As mention, the only seen drawback are the "hard" coded error messages. Here is a small diff on your current JS to allow you to use the title elemement of the form as an error message.

Regards,

xav
-------------------------------------------

# diff -Naur validation.js validation.js.1
--- validation.js 2006-05-18 13:45:29.000000000 +0200
+++ validation.js.1 2006-05-30 20:27:34.000000000 +0200
@@ -74,7 +74,12 @@
var advice = Validation.getAdvice(name, this.id);
if(typeof advice == 'undefined') {
advice = document.createElement('div');
+  // title
+  if(this.title) {
+   advice.appendChild(document.createTextNode(this.title));
+ } else {
  advice.appendChild(document.createTextNode(v.error));
+   }
advice.className = 'validation-advice';
advice.id = 'advice-' + name + '-' + this.id;
advice.style.display = 'none';

#74
On the May 31, 2006, Andrew Tetlaw wrote:

Hi xav, the current version does include the 'custom advice' feature where you can put your error advice within any element on the page.

Thanks for the code, using the element's title has been mentioned before too and you've provided the code to do it!

Ain't open source grand :)

#75
On the May 31, 2006, tanvir wrote:

hi, thnx for the very handy and cool validation frameworks. but i noticed the 'validate-date-au' cannot determine leapyears.
so i suggest u to change the date validator some thing like following:

['validate-date-au', 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.', function(v) {
if(Validation.get('IsEmpty').test(v)) return true;
var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
if(! regex.test(v)) return false;
var d = new Date(v.replace(regex, '$2/$1/$3'));
return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) 
&& (parseInt(RegExp.$1, 10) == d.getDate()) 
&& (parseInt(RegExp.$3, 10) == d.getFullYear()
);
}]


thanks.. keep up nice works.

#76
On the June 1, 2006, TomHung wrote:

validate phone numbers:
339-4248
339-42-48
339 42 48
339 4248
3394248
(095) #phone#
(095)#phone#
+7 (095) #phone#
+7 (095)#phone#
+7(095) #phone#
+7(095)#phone#

['validate-phone', 'Please enter a valid phone number. For example (123) 456-789', function(v) {
return Validation.get('IsEmpty').test(v) || /^(\+\d)*\s*(\(\d{3}\)\s*)*\d{3}(-{0,1}|\s{0,1})\d{2}(-{0,1}|\s{0,1})\d{2}$/.test(v);
}],

#77
On the June 1, 2006, Jim Amos wrote:

Excellent work, but hows about validating select box's and radio buttons? If only to see if they're empty or not..

#78
On the June 2, 2006, eddy wrote:

Hi everybody
I have played around the validation code is uses a semilar aproch
Well I dont think it’s perferct yet
known issue:
suppose we put 2 validation conditions if one is true the input is then valide even the second condition is false

please take a look at the script let me think what do you think about it and how we can improve it together.

you can see a demo and download the script at http://www.tus.com.tn/area51/lab/vf/vf.htm

you can host it here if you want since it’s my company’s site

#79
On the June 6, 2006, xav wrote:

Hello,

I'm style playing with your well done simple form validation script.

I noticed that on Konqueror (the linux geek browser) the script is not working. I figured out that the following line is causing problems :

this.parentNode.insertBefore(advice, this.nextSibling);

Konqueror seems not to handle this.

Using the "new Insertion.After" method instead is fixing the problme with Konqueror and has no consequence on other browsers.

This change required some minors changes on the "test" function. Don't hesitate to contact me for full code.

Regards,

xav

#80
On the June 7, 2006, Santiago wrote:

Great work, thanks!

@ #65, Phil:
Hi, i have one cuestion. How do you make your "equal-to" validation work? I don't get how you pass the name of the field you want to validate against.

#81
On the June 7, 2006, Santiago wrote:

Something else only. "email@example.com " doesn't validate. You should trim spaces in every string.

BTW, I hope someone comes up with an equalto validation. I've tried to do it myself but my js knowledge is soooooo limited...

#82
On the June 7, 2006, Philippe Mouawad wrote:

Hello,
Great Job.
Here is a patch that does the following:
In your initial work, ids are mandatory, I removed this by modifying getAdvice and taking the hypthesis that the advice is always next to the checked node and that the node has the class validation-advice.
I also changed some functions to make the code work with prototype 1.4
I finally removed the addition/removal of validation-passed class
I also encountered some problems with the code type of XXXX == 'undefined', that I replaced with XXXX ==  undefined

Here is the patch.
Philippe.
Index: validation.js
===================================================================
RCS file: /PMD/CVSRepository/fwk-3/webapp/fwk/js/fwk/validation/validation.js,v
retrieving revision 1.1
diff -u -r1.1 validation.js
--- validation.js 6 Jun 2006 20:52:31 -0000 1.1
+++ validation.js 6 Jun 2006 21:00:38 -0000
@@ -22,23 +22,34 @@
}
}

-var Validation = Class.create();
+Validation = Class.create();

Validation.prototype = {
initialize : function(form, options){
- this.options = Object.extend({
- stopOnFirst : false,
- immediate : false,
- focusOnError : true
- }, options || {});
+ this.setOptions(options);
this.form = $(form);
- Event.observe(this.form,'submit',this.onSubmit.bind(this),false);
- if(this.options.immediate) {
- Form.getElements(this.form).each(function(input) { // Thanks Mike!
- Event.observe(input, 'blur', function(ev) { Validation.validate(Event.element(ev).id) });
+ if(this.options.validateOnSubmit)
+ {
+ Event.observe(this.form,'submit',this.onSubmit.bind(this),false);
+ }
+ if(this.options.immediate)
+ {
+ Form.getElements(this.form).each(function(input)
+ {
+ Event.observe(input, 'blur', function(ev) { Validation.validate(Event.element(ev)) });
});
}
},
+ setOptions : function(options)
+ {
+ this.options =
+ {
+   stopOnFirst : false,
+   immediate : false,
+   validateOnSubmit : false,
+ focusOnError : true
+ }.extend(options || {});   
+ },
onSubmit :  function(ev){
if(!this.validate()) {
Event.stop(ev);
@@ -63,7 +74,7 @@
validate : function(elm, index, options){ // index is here only because we use this function in Enumerations
var options = Object.extend({}, options || {}); // options still under development and here as a placeholder only
elm = $(elm);
- var cn = elm.classNames();
+ var cn = Element.classNames(elm);
return result = cn.all(Validation.test.bind(elm));
},
test : function(name) {
@@ -71,59 +82,69 @@
var prop = '__advice'+name.camelize();
if(Validation.isVisible(this) && !v.test($F(this))) {
if(!this[prop]) {
- var advice = Validation.getAdvice(name, this.id);
- if(typeof advice == 'undefined') {
+ var advice = Validation.getAdvice(name, this.id, this);
+ if(advice == undefined) {
advice = document.createElement('div');
advice.appendChild(document.createTextNode(v.error));
advice.className = 'validation-advice';
- advice.id = 'advice-' + name + '-' + this.id;
- advice.style.display = 'none';
+ // We make the Validation work even if id is not defined
+ if(this.id != null)
+ {
+ advice.id = 'advice-' + name + '-' + this.id;
+ }
+ //advice.style.display = 'none';
this.parentNode.insertBefore(advice, this.nextSibling);
}
- if(typeof Effect == 'undefined') {
+ if(Effect == undefined) {
advice.style.display = 'block';
} else {
new Effect.Appear(advice.id, {duration : 1 });
}
}
+
this[prop] = true;
- this.removeClassName('validation-passed');
- this.addClassName('validation-failed');
+ //Element.removeClassName(this,'validation-passed');
+ Element.addClassName(this,'validation-failed');
return false;
} else {
- var advice = Validation.getAdvice(name, this.id);
- if(typeof advice != 'undefined') advice.hide();
- this[prop] = '';
- this.removeClassName('validation-failed');
- this.addClassName('validation-passed');
+ var advice = Validation.getAdvice(name, this.id, this);
+ if(advice != undefined)
+ {
+ Element.hide(advice);
+ }
+ this[prop] = false;
+ Element.removeClassName(this, 'validation-failed');
+ //Element.addClassName(this,'validation-passed');
return true;
}
},
isVisible : function(elm) {
while(elm.tagName != 'BODY') {
- if(!$(elm).visible()) return false;
+ if(!Element.visible(elm)) return false;
elm = elm.parentNode;
}
return true;
},
- getAdvice : function(name, id) {
+ getAdvice : function(name, id, elm) {
var advice = Try.these(
+ // We make the Validation work even if id is not defined
+ function(){ if(Element.classNames(elm.nextSibling).toString().indexOf('validation-advice')>=0) return elm.nextSibling; },
function(){ return $('advice-' + name + '-' + id) },
function(){ return $('advice-' + id) }
);
return advice;
},
reset : function(elm) {
- var cn = elm.classNames();
+ var cn = Element.classNames(elm);
cn.each(function(value) {
var prop = '__advice'+value.camelize();
if(elm[prop]) {
var advice = Validation.getAdvice(value, elm.id);
- advice.hide();
+ Element.hide(advice);
elm[prop] = '';
}
- elm.removeClassName('validation-failed');
- elm.removeClassName('validation-passed');
+ Element.removeClassName(elm, 'validation-failed');
+ //Element.removeClassName(elm, 'validation-passed');
});
},
add : function(className, error, test, options) {

#83
On the June 8, 2006, djcomplex wrote:

To: Philippe Mouawad

Nice work.
Could I download not only the diff?
It would be great if it works with 1.4, too.

Thank you!

#84
On the June 8, 2006, Evan Barash wrote:

Great stuff Andrew!

Im trying to modify Phil(65) script so that it can be used to validate a date range (starting and ending date) so that the end date is more recent than the starting date. 

I then decided to hold off on the date validation until i could get the field comparison to work properly using Phil's(65) code as he posted it...

Like Santiago(81), I cannot get it to work;
the fields validate as being equal even when they are not.

Any idears?!?

#85
On the June 8, 2006, SOSensible wrote:

OK... how do we validate the form fields as we exit the individual fields. (Rather than just waiting to validate the whole form?)

#86
On the June 8, 2006, thkl wrote:

I would like to ask is it possible to handle checking which it will depends on the value input for another fields. That is if the 'NAME' field of the form input, then all elements in the form are required, otherwise they are optional.  Thanks!

#87
On the June 8, 2006, John Farrar wrote:

It seems like there should be ability to check the fields as you go rather than just on a form submit. (Which I mentioned above, but this way you can answer two posts at the same time.)

Also, it also seems like we should be able to use callbacks to trigger other functions upon failures (or success). This would be key to allowing selective actions for good data to do things like ajax calls. (One senario would be sending the whole form on a successful validation. Another would be to validate the values of a field and upon certain conditions it would trigger a function for things like populating a select box via ajax.) This is a validation triggered event, and it is a good way to do things.

#88
On the June 9, 2006, Evan Barash wrote:

For anyone interested in a date validation for MMDDYY format, I have modified the stock validate-date code. I am by no means a javascript/ajax programmer, so this is by no means a brain buster, just thought someone may find it useful.

---------------------------------------------

['validate-date', 'Please use this date format: mmddyy. For example 031706 for March 17, 2006.', function(v) {
if(!Validation.get('IsEmpty').test(v)) {
var upper = 31;
if(/^(\d{2})(\d{2})(\d{2})$/.test(v)) { // mmddyy /^(\d{2})\/(\d{2})\/(\d{2})$/ <-- original regexp w/ slashes
if(RegExp.$1 == '02') upper = 29;
if((RegExp.$1 <= 12) && (RegExp.$2 <= upper)) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return true;
}
}],

#89
On the June 9, 2006, Andrew Tetlaw wrote:

John and SoSensible, from teh article above:
"You can also pass the option {immediate : true} to enable field valiation when leaving each field. That is on the onblur event for all the form elements."

#90
On the June 9, 2006, Evan Barash wrote:

Any ideas as to how radio/checkbox groups can be validated so that if 1 or more is selected in a given group, pass validation...else, spit back an error message?

Just wondering if it can be done with the TITLE tag where each element in your "group" would be checked to see what group they were a part of by naming them as such: TITLE="group1[contact]"

A fantastic AJAX script implements this sort of method is Lightbox2.0 by Lokesh Dhakar

http://www.huddletogether.com/projects/lightbox2/

His script implements the same idea using the rel="" attribute within <img> tags to group images together.

Just an idea.

#91
On the June 12, 2006, Phill Howson wrote:

Hi Evan (85) and Santiago (81),

Sorry for the inconvenience, the equalto validation as posted doesn't work, so try this replacement:
['validate-equalto', 'Please ensure these values are equal', function(v) {
var elmEqualto = $$("input.validate-equalto");
return (elmEqualto[0].value) === (elmEqualto[1].value);
}]

Looks like there are a few of us needing an equalto validator, I hope Andrew has time to work on this ;-) Be warned, my attempt to solve this is a hack, but if you *have* to use it, here's an explanation. I couldn't find a way of passing both the values I needed to the validation function. So two form elements are given the class 'validate-equalto'. Then the line...

var elmEqualto = $$("input.validate-equalto");;

... grabs an array of the elements on the page with the classname 'validate-equalto'. The values of the 2 elements are then compared on the next line and a true/false response generated.

This approach makes a the assumption that there are only 2 elements on the page with the 'validate-equalto' classname, for instance 'email' and 'repeat-email'. If you try to run two equalto comparisons on the same page only the first will be validated. Also it is inefficient as the validation is called on each input element with a 'validate-equalto' classname.

Hope this answers your queries, regards,
Phill

#92
On the June 14, 2006, Tarwin wrote:

Hi,

Thanks for the great script. I thought I'd post a rule I've been using - it forces that 'at least 1' field is not empty (or in the case of a checkbox, checked). The only problem so far is that you can only have 1 'group' of these on a page, though I havn't needed any more than that so far.

This validation routine was made really easy by prototype's $F and getElementsByClassName function!

Validation.add('validate-at-least-one', 'At least one field must be complete.', function (v) {
var fields = getElementsByClassName('validate-at-least-one');
fields.each( function(field){
if ($F(field)) return(true);
});
return false;
});

#93
On the June 15, 2006, Evan Barash wrote:

Thanks Phil, looks good. I will give it a go; fortunately I don't have a need to match two sets of fields, so your workaround is just dandy.

#94
On the June 16, 2006, CK wrote:

This is another question regarding #61

It seems like the demo is not validation both elements (class="required validate-email"). The validate-email element works great by itself but combined with required, it doesn't. Does anyone know why? Thanks 

#95
On the June 16, 2006, Alan wrote:

(96) it seems as though the problem was introduced in version 1.5, because i still have a copy of 1.4 that works with multiple validations. if anyone knows why it quit working, this should be addressed. thanks.

#96
On the June 16, 2006, atany wrote:

I experience the problem with version 1.5 too.
This error happens when form fields contain multiple class names.
This is because the 'return' statement is missing in cn.all() cycle. Hence it will always return false and skip calling other then the first validators in the list.

Here's working modification of Validation.validate function:

==================================
validate : function(elm, options){
options = Object.extend({
useTitle : false
}, options || {});
elm = $(elm);
var cn = elm.classNames();
return result = cn.all(function(value) {
return Validation._testClassName(value,elm,options.useTitle);
});
},
===================================

#97
On the June 16, 2006, Andrew Tetlaw wrote:

Oops, I'm an idiot.

#98
On the June 16, 2006, Alan wrote:

nice work atany... btw, i still haven't found a good phone number checker, so i wrote one. i wanted something flexible enough to accept more than just (555) 555-5555 because quite frankly we shouldn't make the user try over and over to get the format right, if anything we should take what they give us if it's close and then format it the way we want. so here's my contribution:

['validate-phone', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) {
return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v);
}]

it will accept any of the following formats:
555-555-5555
555 555 5555
(555)555-5555
(555)555 5555
(555) 555-5555
(555) 555 5555

or i suppose any combination like the ones above. basically i was interested in just getting an area code and a 7 digit number from the user... the format doesn't matter to me, because we can always format it before using it or storing it. any ideas or suggestions let me know as this is my first reg exp!

#99
On the June 16, 2006, Craig wrote:

how would I go about adding a function for checking validate-checkboxes I'm unsure how I would add this function to this library, great work aswell this is one of the most clean validation checks I've seen its a blessing 
Thanks for the great work keep it up.

#100
On the June 16, 2006, wouaren wrote:

Hi, i added password length verification :
//var $V = Validation.validate;
//var $VG = Validation.get;
//var $VA = Validation.add;

Validation.add('IsEmpty', '', function(v) {
return ((v == null) || (v.length == 0) || /^\s+$/.test(v));
});

Validation.add('IsShort', '', function(v) {
return ((v == null) || (v.length < 6) || /^\s+$/.test(v));
});

Validation.addAllThese([
['required', 'Ce champ ne peut être vide.', function(v) {
return !Validation.get('IsEmpty').test(v);
}],
['validate-mdp', 'Votre mot de passe est trop court', function(v) {
return !Validation.get('IsShort').test(v);
}],

if you dont know where to add this, mail me ;)

Random outings from a chaotic mind

The Dexagogo Rocket Australian Web Industry Association logo

Delicious

Twitter