I've been working on a live form validation project, initially I intended on finding a way to solely use CSS for said validation but it quickly became apparent I would require some jQuery to get it to function properly. That said, I'd like another set of eyes on my jQuery to see if anyone has improvements or tips to streamline it a little better. It seems like there is an awful lot of code repetition but I'm not sure how to best minimize that.
You can see it all together here, if you'd like to offer improvements for the HTML/CSS then by all means have at it but my primary concern is the jquery below since I haven't polished the styles yet.
Disclaimer: This is a work in progress, so there are not fallbacks/polyfills for older browsers at this time.
function supportsHtml5Validation() {
return typeof document.createElement('input').checkValidity === 'function';
}
$(document).ready(function () {
if (supportsHtml5Validation()) {
//delay invalid.
$('input[required]:not([type=radio])').typeWatch({
wait: 300,
captureLength: 1,
callback: function (value) {
// if not valid
if (!this.checkValidity()) {
$(this).addClass('invalid').removeClass('valid');
// if is valid
} else if (this.checkValidity()) {
$(this).on('focusout keyup change', function () {
$(this).removeClass('invalid');
});
}
// if empty clear
if ($(this).val() === '') {
$(this).removeClass('invalid');
}
// remove overlap classing
if ($(this).hasClass('valid')) {
$(this).on('focusout', function () {
$(this).removeClass('invalid');
});
}
}
});
// instantly show if valid
$('input[required]:not([type=radio])').on('keyup change focusout', function () {
if (this.checkValidity()) {
$(this).addClass('valid').removeClass('invalid');
}
});
$('select').on('change', function () {
if (this.checkValidity()) {
$(this).addClass('valid').removeClass('invalid');
} else if (!this.checkValidity()) {
$(this).addClass('invalid').removeClass('valid');
}
});
// remove styling if empty
if ($('input[required]:not([type=radio])').val() === '') {
$(this).on('keyup focusout change', function () {
$(this).removeClass('invalid').removeClass('valid');
});
}
//validate on submit
$(document).on('submit', 'form', function (e) {
$('input[required]:not([type=radio]), select').each(function(){
if (!this.checkValidity()) {
e.preventDefault();
$(this).addClass('invalid');
} else if (this.checkValidity()) {
$(this).addClass('valid');
}
});
// style parent container if :not:checked
$('.group').each(function(){
if($(this).find('input[type=radio]').not(':checked')) {
$(this).closest('.field').addClass('invalid-radio');
}
if($(this).find('input[type=radio]').is(':checked')) {
$(this).closest('.field').removeClass('invalid-radio');
}
$('input[type=radio]').on('change', function(){
$(this).closest('.field').removeClass('invalid-radio');
});
});
// remove styles from <select>'s on form reset
$("input[type=reset]").on("click", function(){
$(".select").removeClass('valid');
});
});
//:not:requred validates on focusin
if($('input').not('[required]')){
$('input:not([required])').on('focusin keyup', function(){
if (this.checkValidity()) {
$(this).addClass('valid').removeClass('invalid');
} else if (!this.checkValidity()) {
$(this).addClass('invalid').removeClass('valid');
}
});
$(this).on('keyup change focusout', function(){
if ($(this).val() === ''){
$(this).removeClass('invalid').removeClass('valid');
}
});
}
} else {
// ...for now
}
});