* This allows for multiple form errors per input, though if none are found, no form errors will be shown.
*
* @param {Object} $el - jQuery object to use as reference to find the form error selector.
+ * @param {String[]} [failedValidators] - List of failed validators.
* @returns {Object} jQuery object with the selector.
*/
- findFormError($el) {
+ findFormError($el, failedValidators) {
var id = $el.length ? $el[0].id : '';
var $error = $el.siblings(this.options.formErrorSelector);
$error = $error.add(this.$element.find(`[data-form-error-for="${id}"]`));
}
+ if (!!failedValidators) {
+ $error = $error.not('[data-form-error-on]')
+
+ failedValidators.forEach((v) => {
+ $error = $error.add($el.siblings(`[data-form-error-on="${v}"]`));
+ $error = $error.add(this.$element.find(`[data-form-error-for="${id}"][data-form-error-on="${v}"]`));
+ });
+ }
+
return $error;
}
/**
* Adds the CSS error class as specified by the Abide settings to the label, input, and the form
* @param {Object} $el - jQuery object to add the class to
+ * @param {String[]} [failedValidators] - List of failed validators.
*/
- addErrorClasses($el) {
+ addErrorClasses($el, failedValidators) {
var $label = this.findLabel($el);
- var $formError = this.findFormError($el);
+ var $formError = this.findFormError($el, failedValidators);
if ($label.length) {
$label.addClass(this.options.labelErrorClass);
*/
validateInput($el) {
var clearRequire = this.requiredCheck($el),
- validated = false,
- customValidator = true,
validator = $el.attr('data-validator'),
- equalTo = true;
+ failedValidators = [],
+ manageErrorClasses = true;
// skip validation if disabled
if (this._validationIsDisabled()) {
switch ($el[0].type) {
case 'radio':
- validated = this.validateRadio($el.attr('name'));
+ this.validateRadio($el.attr('name')) || failedValidators.push('required');
break;
case 'checkbox':
- validated = this.validateCheckbox($el.attr('name'));
- clearRequire = true;
+ this.validateCheckbox($el.attr('name')) || failedValidators.push('required');
+ // validateCheckbox() adds/removes error classes
+ manageErrorClasses = false;
break;
case 'select':
case 'select-one':
case 'select-multiple':
- validated = clearRequire;
+ clearRequire || failedValidators.push('required');
break;
default:
- validated = this.validateText($el);
+ clearRequire || failedValidators.push('required');
+ this.validateText($el) || failedValidators.push('pattern');
}
if (validator) {
- customValidator = this.matchValidation($el, validator, $el.attr('required'));
+ const required = $el.attr('required') ? true : false;
+
+ validator.split(' ').forEach((v) => {
+ this.options.validators[v]($el, required, $el.parent()) || failedValidators.push(v);
+ });
}
if ($el.attr('data-equalto')) {
- equalTo = this.options.validators.equalTo($el);
+ this.options.validators.equalTo($el) || failedValidators.push('equalTo');
}
-
- var goodToGo = [clearRequire, validated, customValidator, equalTo].indexOf(false) === -1;
+ var goodToGo = failedValidators.length === 0;
var message = (goodToGo ? 'valid' : 'invalid') + '.zf.abide';
if (goodToGo) {
}
}
- this[goodToGo ? 'removeErrorClasses' : 'addErrorClasses']($el);
+ if (manageErrorClasses) {
+ this.removeErrorClasses($el);
+
+ if (!goodToGo) {
+ this.addErrorClasses($el, failedValidators);
+ }
+ }
/**
* Fires when the input is done checking for validation. Event trigger is either `valid.zf.abide` or `invalid.zf.abide`
// A pattern can be passed to this function, or it will be infered from the input's "pattern" attribute, or it's "type" attribute
pattern = (pattern || $el.attr('data-pattern') || $el.attr('pattern') || $el.attr('type'));
var inputText = $el.val();
- var valid = false;
+ var valid = true;
if (inputText.length) {
// If the pattern attribute on the element is in Abide's list of patterns, then test that regexp
else if (pattern !== $el.attr('type')) {
valid = new RegExp(pattern).test(inputText);
}
- else {
- valid = true;
- }
- }
- // An empty field is valid if it's not required
- else if (!$el.prop('required')) {
- valid = true;
}
return valid;
// Refresh error class for all input
$group.each((i, e) => {
if (!valid) {
- this.addErrorClasses($(e));
+ this.addErrorClasses($(e), ['required']);
} else {
this.removeErrorClasses($(e));
}
--- /dev/null
+<!doctype html>
+<!--[if IE 9]><html class="lt-ie10" lang="en" > <![endif]-->
+<html class="no-js" lang="en" dir="ltr">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+ <title>Foundation for Sites Testing</title>
+ <link href="../assets/css/foundation.css" rel="stylesheet" />
+ </head>
+ <body>
+ <div class="grid-container">
+ <div class="grid-x grid-padding-x">
+ <div class="cell">
+ <h1>Abide: Error Messages</h1>
+
+ <p>This form has two different error messages.</p>
+
+ <form data-abide novalidate>
+ <label>
+ <input required type="email" placeholder="Email Required">
+ <span class="form-error" data-form-error-on="required">Required</span>
+ <span class="form-error" data-form-error-on="pattern">Invalid</span>
+ </label>
+ <button type="submit" class="button">Submit</button>
+ <button type="reset" class="button">Reset</button>
+ </form>
+
+ <hr>
+
+ <p>This form has two different error messages and uses the [data-form-error-for] attribute to specify the target input.</p>
+
+ <form data-abide novalidate>
+ <label for="url">Url
+ <input required id="url" type="url" placeholder="Url Required">
+ </label>
+ <span class="form-error" data-form-error-for="url" data-form-error-on="required">Required</span>
+ <span class="form-error" data-form-error-for="url" data-form-error-on="pattern">Invalid</span>
+ <button type="submit" class="button">Submit</button>
+ <button type="reset" class="button">Reset</button>
+ </form>
+
+ <hr>
+
+ <p>This form has one generic and one validator-specific error message.</p>
+
+ <form data-abide novalidate>
+ <label>
+ <input required type="email" placeholder="Email Required">
+ <span class="form-error">Error</span>
+ <span class="form-error" data-form-error-on="pattern">Invalid</span>
+ </label>
+ <button type="submit" class="button">Submit</button>
+ <button type="reset" class="button">Reset</button>
+ </form>
+
+ <hr>
+
+ <p>This form uses the equalTo validator.</p>
+
+ <form data-abide novalidate>
+ <label>
+ <input required id="email" type="email" placeholder="Email Required">
+ <span class="form-error">Error</span>
+ </label>
+ </label>
+ <input type="email" placeholder="Email Confirmation" data-equalto="email">
+ <span class="form-error" data-form-error-on="pattern">Invalid</span>
+ <span class="form-error" data-form-error-on="equalTo">Mismatch</span>
+ </label>
+ <button type="submit" class="button">Submit</button>
+ <button type="reset" class="button">Reset</button>
+ </form>
+
+ <hr>
+
+ <p>This form has two input fields.</p>
+
+ <form data-abide novalidate>
+ <label>Email
+ <input required type="email" placeholder="Email Required">
+ <span class="form-error" data-form-error-on="required">Required</span>
+ <span class="form-error" data-form-error-on="pattern">Invalid</span>
+ </label>
+ <label>Url
+ <input required type="url" placeholder="Url Required">
+ <span class="form-error" data-form-error-on="required">Required</span>
+ <span class="form-error" data-form-error-on="pattern">Invalid</span>
+ </label>
+ <button type="submit" class="button">Submit</button>
+ <button type="reset" class="button">Reset</button>
+ </form>
+
+ <hr>
+
+ <p>This form uses a custom validator.</p>
+
+ <form data-abide novalidate>
+ <label>
+ <input required type="number" placeholder="Positive Number Required" data-validator="positive">
+ <span class="form-error" data-form-error-on="required">Required</span>
+ <span class="form-error" data-form-error-on="positive">Must be positive</span>
+ </label>
+ <button type="submit" class="button">Submit</button>
+ <button type="reset" class="button">Reset</button>
+ </form>
+ </div>
+ </div>
+ </div>
+
+ <script src="../assets/js/vendor.js"></script>
+ <script src="../assets/js/foundation.js"></script>
+ <script>
+ Foundation.Abide.defaults.validators['positive'] = function($el) {
+ return parseInt($el.val()) > 0;
+ }
+ $(document).foundation();
+ </script>
+ </body>
+</html>