Skip to content

Instantly share code, notes, and snippets.

@brianmario
Created January 31, 2009 04:58
Show Gist options
  • Save brianmario/55442 to your computer and use it in GitHub Desktop.
Save brianmario/55442 to your computer and use it in GitHub Desktop.
jQuery form validation plugin
//
// validatesPresence
//
// This validator ensures value presence
// The default options are:
//
// invalidClass: 'invalid-presence',
// blankValue: '',
// when: callBack(context)
// validatesOn: ['change', 'blur']
//
//
// invalidClass: the css class to add to the element(s) when validation fails
// blankValue: allows you to specify the value to compare against for testing "blankness"
// when: this callback function should return true/false depending on whether this validation should be run
// it's passed the current jQuery object (context)
// validatesOn: an array of events to trigger validation on
//
jQuery.fn.validatesPresence = function(options) {
return this.each(function() {
var el = $(this);
var settings = jQuery.extend({
invalidClass: 'invalid-presence',
blankValue: '',
when: function() {return true;},
validatesOn: ['change', 'blur']
}, options);
el.bind(settings.validatesOn.join(' '), function(e) {
if (settings.when(el)) {
if ((el.val() === settings.blankValue) || (el.get(0).type == 'checkbox' && !el.attr('checked'))) {
el.trigger('invalid')
.trigger('invalid-presence')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-presence')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
}
});
});
};
// This is our default set of validation formats to be used with the validatesFormat function
jQuery.validationFormats = {
email: {
validationRegex: /([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})/i
},
subDomain: {
validationRegex: /[^a-z0-9-]/i,
invertRule: true
}
};
//
// validatesFormat
//
// This validator ensures value format
// The default options are:
//
// invalidClass: 'invalid-format',
// validationRegex: ".*",
// validatesOn: ['change'],
// invertRule: false
// when: callBack(context)
//
//
// invalidClass: the css class to add to the element(s) when validation fails
// validationRegex: this is the regex string used for testing validation
// validatesOn: an array of events to trigger validation on
// invertRule: a boolean that determines if a match is required or not. False means a match must be found, True means no match can be found
// when: this callback function should return true/false depending on whether this validation should be run
// it's passed the current jQuery object (context)
//
jQuery.fn.validatesFormat = function(options) {
return this.each(function() {
var el = $(this);
var settings = jQuery.extend({
invalidClass: 'invalid-format',
validationRegex: ".*",
validatesOn: ['change', 'blur'],
invertRule: false,
when: function() {return true;}
}, options);
el.bind(settings.validatesOn.join(' '), function(e) {
if (settings.when(el)) {
if (el.val() !== '') {
var match = el.val().match(settings.validationRegex);
if (settings.invertRule) {
if (match !== null) {
el.trigger('invalid')
.trigger('invalid-format')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-format')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
} else {
if (match === null) {
el.trigger('invalid')
.trigger('invalid-format')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-format')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
}
} else {
el.closest('fieldset')
.removeClass(settings.invalidClass);
}
}
});
});
};
//
// validatesLength
//
// This validator ensures value length
// The default options are:
//
// invalidClass: 'invalid-length',
// minimum: null,
// maximum: null,
// validatesOn: ['change', 'blur'],
// when: callBack(context)
//
//
// invalidClass: the css class to add to the element(s) when validation fails
// minimum: the tested value must be greater than this value to be valid
// maximum: the tested value must be less than this value to be valid
// validatesOn: an array of events to trigger validation on
// when: this callback function should return true/false depending on whether this validation should be run
// it's passed the current jQuery object (context)
//
jQuery.fn.validatesLength = function(options) {
return this.each(function() {
var el = $(this);
var settings = jQuery.extend({
invalidClass: 'invalid-length',
minimum: null,
maximum: null,
validatesOn: ['change', 'blur'],
when: function() {return true;}
}, options);
el.bind(settings.validatesOn.join(' '), function(e) {
if (settings.when(el)) {
var valid = true;
if (settings.minimum !== null && el.val().length < settings.minimum) {
valid = false;
}
if (settings.maximum !== null && el.val().length > settings.maximum) {
valid = false;
}
if (!valid) {
el.trigger('invalid')
.trigger('invalid-length')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-length')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
}
});
});
};
//
// validatesNumericality
//
// This validator ensures value numericality
// The default options are:
//
// invalidClass: 'invalid-length',
// onlyInteger: false,
// validatesOn: ['change', 'blur'],
// when: callBack(context)
//
//
// invalidClass: the css class to add to the element(s) when validation fails
// onlyInteger: if this is true, validation success will be limited to integer values only
// allowBlank: if this is true, validation won't be attempted if the value passes it's "blankness" test
// blankValue: allows you to specify the value to compare against for testing "blankness"
// validatesOn: an array of events to trigger validation on
// when: this callback function should return true/false depending on whether this validation should be run
// it's passed the current jQuery object (context)
//
jQuery.fn.validatesNumericality = function(options) {
return this.each(function() {
var el = $(this);
// TODO: I18n
var thousandsSep = ',';
var decimalSep = '.';
var settings = jQuery.extend({
invalidClass: 'invalid-numericality',
onlyInteger: false,
validatesOn: ['change', 'blur'],
when: function() {return true;}
}, options);
el.bind(settings.validatesOn.join(' '), function() {
if (settings.when(el)) {
var validationRegex = function() {
if (settings.onlyInteger) {
return "[^0-9]";
} else {
return "[^0-9"+decimalSep+thousandsSep+"]";
}
}();
if (el.val().match(validationRegex) !== null) {
el.trigger('invalid')
.trigger('invalid-numericality')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-numericality')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
}
});
});
};
//
// validatesUniqueness
//
// This plugin will validate uniqueness of the elements value against a local or remote array
// or a custom callback method to determine uniqueness against said local or remote array/object
//
// The custom callback method will be useful in a situation where the array/object isn't a simple
// array of strings to compare against. This callback method *must* return true or false
// The default options are:
//
// invalidClass: 'invalid-uniqueness',
// source: [],
// validatesOn: ['change', 'blur'],
// when: callBack(context)
//
//
// invalidClass: the css class to add to the element(s) when validation fails
// source: if this is an array a match is attempted inside
// if this is a string, it's assumed to be a URL for which to send an ajax request with the
// parameter 'q' who's value is the value of the element in question.
// The response *must* be a JSON array in this case
// validatesOn: an array of events to trigger validation on
// when: this callback function should return true/false depending on whether this validation should be run
// it's passed the current jQuery object (context)
//
jQuery.fn.validatesUniqueness = function(options) {
return this.each(function() {
var el = $(this);
var settings = jQuery.extend({
invalidClass: 'invalid-uniqueness',
source: [],
validatesOn: ['change', 'blur'],
when: function() {return true;}
}, options);
var req = null;
el.bind(settings.validatesOn.join(' '), function(e) {
if (settings.when(el)) {
e.preventDefault();
var formVal = el.val();
var foundMatch = false;
if (formVal !== '') {
if ($.isArray(settings.source)) {
$.each(settings.source, function(i, item) {
if (item === formVal) {
el.trigger('invalid')
.trigger('invalid-uniqueness')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-uniqueness')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
});
} else if (settings.source.toLowerCase) { // assume it's a string, and is a URL to fetch from
// Cancel the pending request so we don't have to wait for it to come back
if (req !== null && req.readyState < 4) {
req.abort();
}
req = $.getJSON(settings.source, 'q='+formVal, function(data) {
if (el.val() === formVal) {
if (data.length > 0) {
el.trigger('invalid')
.trigger('invalid-uniqueness')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-uniqueness')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
}
});
}
}
}
});
});
};
//
// validates
//
// This is for specifying a custom validation function which *must* return true or false
// The default options are:
//
// invalidClass: 'invalid',
// validatesWith: callback(element),
// validatesOn: ['change']
//
//
// invalidClass: the css class to add to the element(s) when validation fails
// validatesWith: a custom callback function which gets passed the element validation is being attempted on
// whcih *must* return true or false depending on validation success or failure
// validatesOn: an array of events to trigger validation on
//
jQuery.fn.validates = function(options) {
return this.each(function() {
var el = $(this);
var settings = jQuery.extend({
invalidClass: 'invalid',
validatesWith: function(el) {
console.log('must pass a validator function');
return false;
},
validatesOn: ['change']
}, options);
el.bind(settings.validatesOn.join(' '), function() {
if (!settings.validatesWith(el)) {
el.trigger('invalid')
.trigger('invalid-uniqueness')
.closest('fieldset')
.addClass(settings.invalidClass);
} else {
el.trigger('valid')
.trigger('valid-uniqueness')
.closest('fieldset')
.removeClass(settings.invalidClass);
}
});
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment