I was working with a reader on my blog post on HTML5 form validation when we ran into an interesting problem with different browsers.
The reader was using a query selector to get a list of all invalid form fields. As an example:
var invalid = $(":invalid");
This little snippet will return all fields that are currently invalid based on whatever validation rules may be in play. In Chrome, he noticed that he got 2 fields in his test form, which he expected. In Firefox though he got 3.
I created a very simple app up on JSBin to replicate this: (I don't normally embed JSBin stuff so hopefully this works!)
Note the use of the "input" event. To test my code, type a character into the field and then delete it. Chrome returns 1 when you empty the field and Firefox returns 2. Why?
I added a loop and console.dir to actually view the items matching the selector. Turns out that in Firefox, the form tag is marked invalid as well. To be honest, that feels more right to me. I haven't checked the spec yet to see who is right, but I can certainly see the logic of it.
So how would you fix it so you can get a real count of the fields? Simple - just make that selector a bit more specific: $("input:invalid"). Of course, this won't work with textareas or selects in play. You can also just loop through the results and ignore a match on the form tag.
Archived Comments
You should be able to skip the loop with
$(":invalid").not("form")
Boom - perfect. Thanks Blaise. I always forget about not() in jQuery.
I think you would also be able to use $("form :input:invalid").
But that has the same issue I mentioned about select/textarea.
$('form :invalid')
@Paul: Did you try that to see if FF still returned the <form> tag?
This is the optimal method I think: $(":invalid", "#myForm"). Here, #myForm is provided as a context, which is what we want to do anyway in a real-world scenario: Find all invalid fields within form X.
Live demo: http://jsfiddle.net/RxLzM/1/ (tested in FF/Ch)
And the screenshot that confirms that the FORM element indeed matches :invalid in Firefox but not in Chrome: http://i.imgur.com/gdcO6i2.png
Note the colon in front of "input". $("form :input:invalid") will catch the textareas and selects as well. See http://api.jquery.com/input....
@Sime, Paul: Thanks guys. So is :invalid a jQuery-ism then?
Answered my own question:
http://api.jquery.com/input...
So happy when a blog post like this leads to new discoveries for me. :)
Nice tid bit Ray. I may try this out since I have been using a javascript textcounter for form validation. This can catch all fields instead of just one. But one more note to add. I thought the preventDefault(); was deprecated.
Are you using textcounter for textareas to specify a maxlength?
preventDefault() - not afail. I could be wrong.
Yep, Got it on my forms with the keyUp and KeyDown functions. You might check the jQuery documentation for the preventDefault(), but I am pretty sure it has been deprecated.
I'm not seeing that here: http://api.jquery.com/event....
I figured it out. It is showing it as deprecated in the Safari console. I knew I saw it somewhere. Since it is on jQuery's website, I must assume it is not deprecated. Thanks for the clarification.
This is documented FireFox behavior: https://developer.mozilla.o.... See apply to form in the bottom section.
But shouldn't we chalk this up as programmer's oversight? Think multiple forms pages: http://jsfiddle.net/RxLzM/12/
Most likely, you should be as specific as you can and you should be looking up invalid fields in the current form instead, e.g. $(e).closest("form").
Well, I suppose you could chalk it up to the programmers mistake, but I see it as something that could have tripped people up. I use the *heck* out of MDN, but I know this facet wasn't known to me either.
True. It is a browser difference.