diff --git a/dist/jcs-auto-validate.js b/dist/jcs-auto-validate.js index 21cebc1..c817124 100644 --- a/dist/jcs-auto-validate.js +++ b/dist/jcs-auto-validate.js @@ -1,936 +1,1517 @@ /* - * angular-auto-validate - v1.0.17 - 2014-08-07 + * angular-auto-validate - v1.19.3 - 2015-11-30 * https://github.com/jonsamwell/angular-auto-validate - * Copyright (c) 2014 Jon Samwell (http://www.jonsamwell.com) + * Copyright (c) 2015 Jon Samwell (http://www.jonsamwell.com) */ -(function (angular) { +(function (String, angular) { 'use strict'; - angular.module('jcs-autoValidate', []); -}(angular)); +angular.module('jcs-autoValidate', []); -(function (angular) { - 'use strict'; +function ValidatorFn() { + var elementStateModifiers = {}, + enableValidElementStyling = true, + enableInvalidElementStyling = true, + enableFirstInvalidElementScrollingOnSubmit = false, + validationEnabled = true, - angular.module('jcs-autoValidate') - .provider('validator', [ - - function () { - var elementStateModifiers = {}, - enableValidElementStyling = true, - enableInvalidElementStyling = true, - - toBoolean = function (value) { - var v; - if (value && value.length !== 0) { - v = value.toLowerCase(); - value = !(v === 'f' || v === '0' || v === 'false'); - } else { - value = false; - } - - return value; - }, - - getAttributeValue = function (el, attrName) { - var val; - - if (el !== undefined) { - val = el.attr(attrName) || el.attr('data-' + attrName); - } - - return val; - }, - - getBooleanAttributeValue = function (el, attrName) { - return toBoolean(getAttributeValue(el, attrName)); - }, - - validElementStylingEnabled = function (el) { - return enableValidElementStyling && !getBooleanAttributeValue(el, 'disable-valid-styling'); - }, - - invalidElementStylingEnabled = function (el) { - return enableInvalidElementStyling && !getBooleanAttributeValue(el, 'disable-invalid-styling'); - }; - - /** - * @ngdoc function - * @name validator#setDefaultElementModifier - * @methodOf validator - * - * @description - * Sets the default element modifier that will be used by the validator - * to change an elements UI state. Please ensure the modifier has been registered - * before setting it as default. - * - * Note: this can be changed by setting the - * element modifier attribute on the input element 'data-element-modifier="myCustomModifier"' - * - * Example: - *
- * app.config(function (validator) {
- * validator.setDefaultElementModifier('myCustomModifier');
- * });
- *
- *
- * @param {string} key The key name of the modifier.
- */
- this.setDefaultElementModifier = function (key) {
- if (elementStateModifiers[key] === undefined) {
- throw new Error('Element modifier not registered: ' + key);
- }
-
- this.defaultElementModifier = key;
- };
+ toBoolean = function (value) {
+ var v;
+ if (value && value.length !== 0) {
+ v = value.toLowerCase();
+ value = !(v === 'f' || v === '0' || v === 'false');
+ } else {
+ value = false;
+ }
- /**
- * @ngdoc function
- * @name validator#registerDomModifier
- * @methodOf validator
- *
- * @description
- * Registers an object that adheres to the elementModifier interface and is
- * able to modifier an elements dom so that appears valid / invalid for a specific
- * scenario i.e. the Twitter Bootstrap css framework, Foundation CSS framework etc.
- *
- * Example:
- *
- * app.config(function (validator) {
- * validator.registerDomModifier('customDomModifier', {
- * makeValid: function (el) {
- * el.removeClass(el, 'invalid');
- * el.addClass(el, 'valid');
- * },
- * makeInvalid: function (el, err, domManipulator) {
- * el.removeClass(el, 'valid');
- * el.addClass(el, 'invalid');
- * }
- * });
- * });
- *
- *
- * @param {string} key The key name of the modifier
- * @param {object} modifier An object which implements the elementModifier interface
- */
- this.registerDomModifier = function (key, modifier) {
- elementStateModifiers[key] = modifier;
- };
+ return value;
+ },
- /**
- * @ngdoc function
- * @name validator#setErrorMessageResolver
- * @methodOf validator
- *
- * @description
- * Registers an object that adheres to the elementModifier interface and is
- * able to modifier an elements dom so that appears valid / invalid for a specific
- * scenario i.e. the Twitter Bootstrap css framework, Foundation CSS framework etc.
- *
- * Example:
- *
- * app.config(function (validator) {
- * validator.setErrorMessageResolver(function (errorKey, el) {
- * var defer = $q.defer();
- * // resolve the correct error from the given key and resolve the returned promise.
- * return defer.promise();
- * });
- * });
- *
- *
- * @param {function} resolver A method that returns a promise with the resolved error message in.
- */
- this.setErrorMessageResolver = function (resolver) {
- this.errorMessageResolver = resolver;
- };
+ getAttributeValue = function (el, attrName) {
+ var val;
- /**
- * @ngdoc function
- * @name validator#getErrorMessage
- * @methodOf validator
- *
- * @description
- * Resolves the error message for the given error type.
- *
- * @param {String} errorKey The error type.
- * @param {Element} el The UI element that is the focus of the error.
- * It is provided as the error message may need information from the element i.e. ng-min (the min allowed value).
- */
- this.getErrorMessage = function (errorKey, el) {
- if (this.errorMessageResolver === undefined) {
- throw new Error('Please set an error message resolver via the setErrorMessageResolver function before attempting to resolve an error message.');
- }
-
- return this.errorMessageResolver(errorKey, el);
- };
+ if (el !== undefined) {
+ val = el.attr(attrName) || el.attr('data-' + attrName);
+ }
- /**
- * @ngdoc function
- * @name validator#setValidElementStyling
- * @methodOf validator
- *
- * @description
- * Globally enables valid element visual styling. This is enabled by default.
- *
- * @param {Boolean} enabled True to enable style otherwise false.
- */
- this.setValidElementStyling = function (enabled) {
- enableValidElementStyling = enabled;
- };
+ return val;
+ },
+ attributeExists = function (el, attrName) {
+ var exists;
- /**
- * @ngdoc function
- * @name validator#setInvalidElementStyling
- * @methodOf validator
- *
- * @description
- * Globally enables invalid element visual styling. This is enabled by default.
- *
- * @param {Boolean} enabled True to enable style otherwise false.
- */
- this.setInvalidElementStyling = function (enabled) {
- enableInvalidElementStyling = enabled;
- };
+ if (el !== undefined) {
+ exists = el.attr(attrName) !== undefined || el.attr('data-' + attrName) !== undefined;
+ }
- this.getDomModifier = function (el) {
- var modifierKey = (el !== undefined ? el.attr('element-modifier') : this.defaultElementModifier) ||
- (el !== undefined ? el.attr('data-element-modifier') : this.defaultElementModifier) ||
- this.defaultElementModifier;
+ return exists;
+ },
- if (modifierKey === undefined) {
- throw new Error('Please set a default dom modifier via the setDefaultElementModifier method on the validator class.');
- }
+ getBooleanAttributeValue = function (el, attrName) {
+ return toBoolean(getAttributeValue(el, attrName));
+ },
- return elementStateModifiers[modifierKey];
- };
+ validElementStylingEnabled = function (el) {
+ return enableValidElementStyling && !getBooleanAttributeValue(el, 'disable-valid-styling');
+ },
- this.makeValid = function (el) {
- if (validElementStylingEnabled(el)) {
- this.getDomModifier(el).makeValid(el);
- }
- };
+ autoValidateEnabledOnControl = function (el) {
+ return !getBooleanAttributeValue(el, 'disable-auto-validate');
+ },
- this.makeInvalid = function (el, errorMsg) {
- if (invalidElementStylingEnabled(el)) {
- this.getDomModifier(el).makeInvalid(el, errorMsg);
- }
- };
+ invalidElementStylingEnabled = function (el) {
+ return enableInvalidElementStyling && !getBooleanAttributeValue(el, 'disable-invalid-styling');
+ };
- this.makeDefault = function (el) {
- var dm = this.getDomModifier(el);
- if (dm.makeDefault) {
- dm.makeDefault(el);
- }
- };
+ /**
+ * @ngdoc function
+ * @name validator#enable
+ * @methodOf validator
+ *
+ * @description
+ * By default auto validate will validate all forms and elements with an ngModel directive on. By
+ * setting enabled to false you will explicitly have to opt in to enable validation on forms and child
+ * elements.
+ *
+ * Note: this can be overridden by add the 'auto-validate-enabled="true/false' attribute to a form.
+ *
+ * Example:
+ *
+ * app.config(function (validator) {
+ * validator.enable(false);
+ * });
+ *
+ *
+ * @param {Boolean} isEnabled true to enable, false to disable.
+ */
+ this.enable = function (isEnabled) {
+ validationEnabled = isEnabled;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#isEnabled
+ * @methodOf validator
+ *
+ * @description
+ * Returns true if the library is enabeld.
+ *
+ * @return {Boolean} true if enabled, otherwise false.
+ */
+ this.isEnabled = function () {
+ return validationEnabled;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#setDefaultElementModifier
+ * @methodOf validator
+ *
+ * @description
+ * Sets the default element modifier that will be used by the validator
+ * to change an elements UI state. Please ensure the modifier has been registered
+ * before setting it as default.
+ *
+ * Note: this can be changed by setting the
+ * element modifier attribute on the input element 'data-element-modifier="myCustomModifier"'
+ *
+ * Example:
+ *
+ * app.config(function (validator) {
+ * validator.setDefaultElementModifier('myCustomModifier');
+ * });
+ *
+ *
+ * @param {string} key The key name of the modifier.
+ */
+ this.setDefaultElementModifier = function (key) {
+ if (elementStateModifiers[key] === undefined) {
+ throw new Error('Element modifier not registered: ' + key);
+ }
- this.$get = [
+ this.defaultElementModifier = key;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#registerDomModifier
+ * @methodOf validator
+ *
+ * @description
+ * Registers an object that adheres to the elementModifier interface and is
+ * able to modifier an elements dom so that appears valid / invalid for a specific
+ * scenario i.e. the Twitter Bootstrap css framework, Foundation CSS framework etc.
+ *
+ * Example:
+ *
+ * app.config(function (validator) {
+ * validator.registerDomModifier('customDomModifier', {
+ * makeValid: function (el) {
+ * el.removeClass(el, 'invalid');
+ * el.addClass(el, 'valid');
+ * },
+ * makeInvalid: function (el, err, domManipulator) {
+ * el.removeClass(el, 'valid');
+ * el.addClass(el, 'invalid');
+ * }
+ * });
+ * });
+ *
+ *
+ * @param {string} key The key name of the modifier
+ * @param {object} modifier An object which implements the elementModifier interface
+ */
+ this.registerDomModifier = function (key, modifier) {
+ elementStateModifiers[key] = modifier;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#setErrorMessageResolver
+ * @methodOf validator
+ *
+ * @description
+ * Registers an object that adheres to the elementModifier interface and is
+ * able to modifier an elements dom so that appears valid / invalid for a specific
+ * scenario i.e. the Twitter Bootstrap css framework, Foundation CSS framework etc.
+ *
+ * Example:
+ *
+ * app.config(function (validator) {
+ * validator.setErrorMessageResolver(function (errorKey, el) {
+ * var defer = $q.defer();
+ * // resolve the correct error from the given key and resolve the returned promise.
+ * return defer.promise();
+ * });
+ * });
+ *
+ *
+ * @param {function} resolver A method that returns a promise with the resolved error message in.
+ */
+ this.setErrorMessageResolver = function (resolver) {
+ this.errorMessageResolver = resolver;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#getErrorMessage
+ * @methodOf validator
+ *
+ * @description
+ * Resolves the error message for the given error type.
+ *
+ * @param {String} errorKey The error type.
+ * @param {Element} el The UI element that is the focus of the error.
+ * It is provided as the error message may need information from the element i.e. ng-min (the min allowed value).
+ */
+ this.getErrorMessage = function (errorKey, el) {
+ var defer;
+ if (this.errorMessageResolver === undefined) {
+ throw new Error('Please set an error message resolver via the setErrorMessageResolver function before attempting to resolve an error message.');
+ }
- function () {
- return this;
- }
- ];
- }
- ]);
-}(angular));
+ if (attributeExists(el, 'disable-validation-message')) {
+ defer = angular.injector(['ng']).get('$q').defer();
+ defer.resolve('');
+ return defer.promise;
+ } else {
+ return this.errorMessageResolver(errorKey, el);
+ }
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#setValidElementStyling
+ * @methodOf validator
+ *
+ * @description
+ * Globally enables valid element visual styling. This is enabled by default.
+ *
+ * @param {Boolean} enabled True to enable style otherwise false.
+ */
+ this.setValidElementStyling = function (enabled) {
+ enableValidElementStyling = enabled;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#setInvalidElementStyling
+ * @methodOf validator
+ *
+ * @description
+ * Globally enables invalid element visual styling. This is enabled by default.
+ *
+ * @param {Boolean} enabled True to enable style otherwise false.
+ */
+ this.setInvalidElementStyling = function (enabled) {
+ enableInvalidElementStyling = enabled;
+ };
+
+ /**
+ * @ngdoc function
+ * @name validator#setFirstInvalidElementScrollingOnSubmit
+ * @methodOf validator
+ *
+ * @description
+ * Globally enables first invalid element scrolling on form submit. This is disabled by default.
+ *
+ * @param enabled {Boolean} enabled True to enable scrolling otherwise false.
+ */
+ this.setFirstInvalidElementScrollingOnSubmit = function (enabled) {
+ enableFirstInvalidElementScrollingOnSubmit = enabled;
+ };
+
+ this.firstInvalidElementScrollingOnSubmitEnabled = function () {
+ return enableFirstInvalidElementScrollingOnSubmit;
+ };
+
+
+ this.getDomModifier = function (el) {
+ var modifierKey = (el !== undefined ? el.attr('element-modifier') : this.defaultElementModifier) ||
+ (el !== undefined ? el.attr('data-element-modifier') : this.defaultElementModifier) ||
+ this.defaultElementModifier;
+
+ if (modifierKey === undefined) {
+ throw new Error('Please set a default dom modifier via the setDefaultElementModifier method on the validator class.');
+ }
-(function (angular) {
- 'use strict';
+ return elementStateModifiers[modifierKey];
+ };
- angular.module('jcs-autoValidate')
- .factory('bootstrap3ElementModifier', [
-
- function () {
- var reset = function (el) {
- angular.forEach(el.find('span'), function (spanEl) {
- spanEl = angular.element(spanEl);
- if (spanEl.hasClass('error-msg') || spanEl.hasClass('form-control-feedback')) {
- spanEl.remove();
- }
- });
-
- el.removeClass('has-success has-error has-feedback');
- },
- findFormGroupElement = function (el) {
- var parent = el;
- for (var i = 0; i <= 3; i += 1) {
- if (parent !== undefined && parent.hasClass('form-group')) {
- break;
- } else if (parent !== undefined) {
- parent = parent.parent();
- }
- }
-
- return parent;
- },
-
- insertAfter = function (referenceNode, newNode) {
- referenceNode[0].parentNode.insertBefore(newNode[0], referenceNode[0].nextSibling);
- },
-
- /**
- * @ngdoc property
- * @name bootstrap3ElementModifier#addValidationStateIcons
- * @propertyOf bootstrap3ElementModifier
- * @returns {bool} True if an state icon will be added to the element in the valid and invalid control
- * states. The default is false.
- */
- addValidationStateIcons = false,
-
- /**
- * @ngdoc function
- * @name bootstrap3ElementModifier#enableValidationStateIcons
- * @methodOf bootstrap3ElementModifier
- *
- * @description
- * Makes an element appear invalid by apply an icon to the input element.
- *
- * @param {bool} enable - True to enable the icon otherwise false.
- */
- enableValidationStateIcons = function (enable) {
- addValidationStateIcons = enable;
- },
-
- /**
- * @ngdoc function
- * @name bootstrap3ElementModifier#makeValid
- * @methodOf bootstrap3ElementModifier
- *
- * @description
- * Makes an element appear valid by apply bootstrap 3 specific styles and child elements. If the service
- * property 'addValidationStateIcons' is true it will also append validation glyphicon to the element.
- * See: http://getbootstrap.com/css/#forms-control-validation
- *
- * @param {Element} el - The input control element that is the target of the validation.
- */
- makeValid = function (el) {
- var frmGroupEl = findFormGroupElement(el);
- reset(frmGroupEl);
- frmGroupEl.addClass('has-success has-feedback');
- if (addValidationStateIcons) {
- insertAfter(el, angular.element(''));
- }
- },
-
- /**
- * @ngdoc function
- * @name bootstrap3ElementModifier#makeInvalid
- * @methodOf bootstrap3ElementModifier
- *
- * @description
- * Makes an element appear invalid by apply bootstrap 3 specific styles and child elements. If the service
- * property 'addValidationStateIcons' is true it will also append validation glyphicon to the element.
- * See: http://getbootstrap.com/css/#forms-control-validation
- *
- * @param {Element} el - The input control element that is the target of the validation.
- */
- makeInvalid = function (el, errorMsg) {
- var frmGroupEl = findFormGroupElement(el),
- helpTextEl = angular.element('' + errorMsg + '');
- reset(frmGroupEl);
- frmGroupEl.addClass('has-error has-feedback');
- insertAfter(el, helpTextEl);
- if (addValidationStateIcons) {
- insertAfter(el, angular.element(''));
- }
- },
-
- /**
- * @ngdoc function
- * @name bootstrap3ElementModifier#makeDefault
- * @methodOf bootstrap3ElementModifier
- *
- * @description
- * Makes an element appear in its default visual state by apply bootstrap 3 specific styles and child elements.
- *
- * @param {Element} el - The input control element that is the target of the validation.
- */
- makeDefault = function (el) {
- var frmGroupEl = findFormGroupElement(el);
- reset(frmGroupEl);
- };
-
- return {
- makeValid: makeValid,
- makeInvalid: makeInvalid,
- makeDefault: makeDefault,
- enableValidationStateIcons: enableValidationStateIcons,
- key: 'bs3'
- };
- }
- ]);
-}(angular));
+ this.makeValid = function (el) {
+ if (autoValidateEnabledOnControl(el)) {
+ if (validElementStylingEnabled(el)) {
+ this.getDomModifier(el).makeValid(el);
+ } else {
+ this.makeDefault(el);
+ }
+ }
+ };
+
+ this.makeInvalid = function (el, errorMsg) {
+ if (autoValidateEnabledOnControl(el)) {
+ if (invalidElementStylingEnabled(el)) {
+ this.getDomModifier(el).makeInvalid(el, errorMsg);
+ } else {
+ this.makeDefault(el);
+ }
+ }
+ };
+
+ this.makeDefault = function (el) {
+ if (autoValidateEnabledOnControl(el)) {
+ var dm = this.getDomModifier(el);
+ if (dm.makeDefault) {
+ dm.makeDefault(el);
+ }
+ }
+ };
+
+ this.waitForAsyncValidators = function (el) {
+ if (autoValidateEnabledOnControl(el)) {
+ var dm = this.getDomModifier(el);
+ if (dm.waitForAsyncValidators) {
+ dm.waitForAsyncValidators(el);
+ }
+ }
+ };
+
+ this.defaultFormValidationOptions = {
+ forceValidation: false,
+ disabled: false,
+ validateNonVisibleControls: false,
+ removeExternalValidationErrorsOnSubmit: true,
+ validateOnFormSubmit: false,
+ waitForAsyncValidators: true
+ };
+
+ this.$get = [
+ function () {
+ return this;
+ }
+ ];
+}
+
+angular.module('jcs-autoValidate').provider('validator', ValidatorFn);
+
+function Bootstrap3ElementModifierFn($log) {
+ var customCss = [
+ ''
+ ].join('');
+
+ angular.element(document.body).append(angular.element(customCss));
+
+ var reset = function (el) {
+ angular.forEach(el.find('span'), function (spanEl) {
+ spanEl = angular.element(spanEl);
+ if (spanEl.hasClass('error-msg') || spanEl.hasClass('form-control-feedback') || spanEl.hasClass('control-feedback')) {
+ spanEl.remove();
+ }
+ });
+
+ el.removeClass('has-success has-error has-feedback');
+ },
+ findWithClassElementAsc = function (el, klass) {
+ var returnEl,
+ parent = el;
+ for (var i = 0; i <= 10; i += 1) {
+ if (parent !== undefined && parent.hasClass(klass)) {
+ returnEl = parent;
+ break;
+ } else if (parent !== undefined) {
+ parent = parent.parent();
+ }
+ }
+
+ return returnEl;
+ },
+
+ findWithClassElementDesc = function (el, klass) {
+ var child;
+ for (var i = 0; i < el.children.length; i += 1) {
+ child = el.children[i];
+ if (child !== undefined && angular.element(child).hasClass(klass)) {
+ break;
+ } else if (child.children !== undefined) {
+ child = findWithClassElementDesc(child, klass);
+ if (child.length > 0) {
+ break;
+ }
+ }
+ }
-(function (angular) {
- 'use strict';
+ return angular.element(child);
+ },
+
+ findFormGroupElement = function (el) {
+ return findWithClassElementAsc(el, 'form-group');
+ },
+
+ findInputGroupElement = function (el) {
+ return findWithClassElementDesc(el, 'input-group');
+ },
+
+ insertAfter = function (referenceNode, newNode) {
+ referenceNode[0].parentNode.insertBefore(newNode[0], referenceNode[0].nextSibling);
+ },
+
+ /**
+ * @ngdoc property
+ * @name bootstrap3ElementModifier#addValidationStateIcons
+ * @propertyOf bootstrap3ElementModifier
+ * @returns {bool} True if an state icon will be added to the element in the valid and invalid control
+ * states. The default is false.
+ */
+ addValidationStateIcons = false,
- /*
- * Taken from https://github.com/angular/angular.js/issues/2690#issue-14462164 (with added tests of course!)
+ /**
+ * @ngdoc function
+ * @name bootstrap3ElementModifier#enableValidationStateIcons
+ * @methodOf bootstrap3ElementModifier
+ *
+ * @description
+ * Makes an element appear invalid by apply an icon to the input element.
+ *
+ * @param {bool} enable - True to enable the icon otherwise false.
*/
- angular.module('jcs-autoValidate').factory('debounce', [
- '$timeout',
- function ($timeout) {
- var debounce = function (fn, timeout, apply) {
- timeout = angular.isUndefined(timeout) ? 0 : timeout;
- apply = angular.isUndefined(apply) ? true : apply; // !!default is true! most suitable to my experience
- var nthCall = 0;
- return function () { // intercepting fn
- var that = this;
- var argz = arguments;
- nthCall += 1;
- var later = (function (version) {
- return function () {
- if (version === nthCall) {
- return fn.apply(that, argz);
- }
- };
- })(nthCall);
-
- return $timeout(later, timeout, apply);
- };
- };
+ enableValidationStateIcons = function (enable) {
+ addValidationStateIcons = enable;
+ },
- return {
- debounce: debounce
- };
+ /**
+ * @ngdoc function
+ * @name bootstrap3ElementModifier#makeValid
+ * @methodOf bootstrap3ElementModifier
+ *
+ * @description
+ * Makes an element appear valid by apply bootstrap 3 specific styles and child elements. If the service
+ * property 'addValidationStateIcons' is true it will also append validation glyphicon to the element.
+ * See: http://getbootstrap.com/css/#forms-control-validation
+ *
+ * @param {Element} el - The input control element that is the target of the validation.
+ */
+ makeValid = function (el) {
+ var frmGroupEl = findFormGroupElement(el),
+ inputGroupEl;
+
+ if (frmGroupEl) {
+ reset(frmGroupEl);
+ inputGroupEl = findInputGroupElement(frmGroupEl[0]);
+ frmGroupEl.addClass('has-success ' + (inputGroupEl.length > 0 || addValidationStateIcons === false ? '' : 'has-feedback'));
+ if (addValidationStateIcons) {
+ var iconElText = '';
+ if (inputGroupEl.length > 0) {
+ iconElText = iconElText.replace('form-', '');
+ iconElText = '' + iconElText + '' + errorMsg + ''),
+ inputGroupEl;
+
+ if (frmGroupEl) {
+ reset(frmGroupEl);
+ inputGroupEl = findInputGroupElement(frmGroupEl[0]);
+ frmGroupEl.addClass('has-error ' + (inputGroupEl.length > 0 || addValidationStateIcons === false ? '' : 'has-feedback'));
+ insertAfter(inputGroupEl.length > 0 ? inputGroupEl : getCorrectElementToPlaceErrorElementAfter(el), helpTextEl);
+ if (addValidationStateIcons) {
+ var iconElText = '';
+ if (inputGroupEl.length > 0) {
+ iconElText = iconElText.replace('form-', '');
+ iconElText = '' + iconElText + '';
+ }
+
+ insertAfter(getCorrectElementToPlaceErrorElementAfter(el), angular.element(iconElText));
+ }
+ } else {
+ $log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
+ }
+ },
+
+ getCorrectElementToPlaceErrorElementAfter = function (el) {
+ var correctEl = el,
+ elType = el[0].type ? el[0].type.toLowerCase() : '';
+
+ if ((elType === 'checkbox' || elType === 'radio') && el.parent()[0].nodeName.toLowerCase() === 'label') {
+ correctEl = el.parent();
+ }
+
+ return correctEl;
+ },
/**
- * Replaces string placeholders with corresponding template string
+ * @ngdoc function
+ * @name bootstrap3ElementModifier#makeDefault
+ * @methodOf bootstrap3ElementModifier
+ *
+ * @description
+ * Makes an element appear in its default visual state by apply bootstrap 3 specific styles and child elements.
+ *
+ * @param {Element} el - The input control element that is the target of the validation.
*/
- if (!('format' in String.prototype)) {
- String.prototype.format = function () {
- var args = arguments;
- return this.replace(/{(\d+)}/g, function (match, number) {
- return typeof args[number] !== undefined ? args[number] : match;
- });
- };
- }
+ makeDefault = function (el) {
+ var frmGroupEl = findFormGroupElement(el);
+ if (frmGroupEl) {
+ reset(frmGroupEl);
+ } else {
+ $log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
+ }
+ },
+
+ waitForAsyncValidators = function (el) {
+ var frmGroupEl = findFormGroupElement(el),
+ inputGroupEl;
+
+ if (frmGroupEl) {
+ reset(frmGroupEl);
+ inputGroupEl = findInputGroupElement(frmGroupEl[0]);
+ frmGroupEl.addClass('has-feedback ' + (inputGroupEl.length > 0 || addValidationStateIcons === false ? '' : 'has-feedback'));
+ if (addValidationStateIcons) {
+ var iconElText = '';
+ if (inputGroupEl.length > 0) {
+ iconElText = iconElText.replace('form-', '');
+ iconElText = '' + iconElText + '';
+ }
+
+ insertAfter(el, angular.element(iconElText));
+ }
+ } else {
+ $log.error('Angular-auto-validate: invalid bs3 form structure elements must be wrapped by a form-group class');
+ }
+ };
+
+ return {
+ makeValid: makeValid,
+ makeInvalid: makeInvalid,
+ makeDefault: makeDefault,
+ waitForAsyncValidators: waitForAsyncValidators,
+ enableValidationStateIcons: enableValidationStateIcons,
+ key: 'bs3'
+ };
+}
+
+Bootstrap3ElementModifierFn.$inject = [
+ '$log'
+];
+
+angular.module('jcs-autoValidate').factory('bootstrap3ElementModifier', Bootstrap3ElementModifierFn);
- angular.autoValidate = angular.autoValidate || {
- errorMessages: {}
+/*
+ * Taken from https://github.com/angular/angular.js/issues/2690#issue-14462164 (with added tests of course!)
+ */
+function JCSDebounceFn($timeout) {
+ var debounce = function (func, wait, immediate) {
+ var timeout;
+ return function () {
+ var context = this;
+ var args = arguments;
+ var later = function () {
+ timeout = null;
+ if (!immediate) {
+ func.apply(context, args);
+ }
+ };
+
+ var callNow = immediate && !timeout;
+ $timeout.cancel(timeout);
+ timeout = $timeout(later, wait, false);
+ if (callNow) {
+ func.apply(context, args);
+ }
};
+ };
+
+ return {
+ debounce: debounce
+ };
+}
+
+JCSDebounceFn.$inject = [
+ '$timeout'
+];
+
+angular.module('jcs-autoValidate').factory('jcs-debounce', JCSDebounceFn);
+
+/**
+ * Replaces string placeholders with corresponding template string
+ */
+if (!('format' in String.prototype)) {
+ String.prototype.format = function () {
+ var args = arguments;
+ return this.replace(/{(\d+)}/g, function (match, number) {
+ return typeof args[number] !== undefined ? args[number] : match;
+ });
+ };
+}
+
+angular.autoValidate = angular.autoValidate || {
+ errorMessages: {}
+};
+
+angular.autoValidate.errorMessages['default'] = {
+ defaultMsg: 'Please add error message for {0}',
+ email: 'Please enter a valid email address',
+ minlength: 'Please enter at least {0} characters',
+ maxlength: 'You have entered more than the maximum {0} characters',
+ min: 'Please enter the minimum number of {0}',
+ max: 'Please enter the maximum number of {0}',
+ required: 'This field is required',
+ date: 'Please enter a valid date',
+ pattern: 'Please ensure the entered information adheres to this pattern {0}',
+ number: 'Please enter a valid number',
+ url: 'Please enter a valid URL in the format of http(s)://www.google.com'
+};
+
+function DefaultErrorMessageResolverFn($q, $http) {
+ var currentCulture = 'default',
+
+ i18nFileRootPath = 'js/angular-auto-validate/dist/lang',
+
+ cultureRetrievalPromise,
+
+ loadRemoteCulture = function (culture) {
+ cultureRetrievalPromise = $http.get('{0}/jcs-auto-validate_{1}.json'.format(i18nFileRootPath, culture.toLowerCase()));
+ return cultureRetrievalPromise;
+ },
+
+ /**
+ * @ngdoc function
+ * @name defaultErrorMessageResolver#setI18nFileRootPath
+ * @methodOf defaultErrorMessageResolver
+ *
+ * @description
+ * Set the root path to the il8n files on the server
+ *
+ * @param {String} rootPath - The root path on the server to the il8n file - this defaults
+ * to 'js/angular-auto-validate/lang/'
+ */
+ setI18nFileRootPath = function (rootPath) {
+ i18nFileRootPath = rootPath;
+ },
- angular.autoValidate.errorMessages['en-us'] = angular.autoValidate.errorMessages['en-gb'] = {
- defaultMsg: 'Please add error message for {0}',
- email: 'Please enter a valid email address',
- minlength: 'Please enter at least {0} characters',
- maxlength: 'You have entered more than the maximum {0} characters',
- min: 'Please enter the minimum number of {0}',
- max: 'Please enter the maximum number of {0}',
- required: 'This field is required',
- date: 'Please enter a valid date',
- pattern: 'Please ensure the entered information adheres to this pattern {0}',
- number: 'Please enter a valid number',
- url: 'Please enter a valid URL in the format of http(s)://wwww.google.com'
+ /**
+ * @ngdoc function
+ * @name defaultErrorMessageResolver#setCulture
+ * @methodOf defaultErrorMessageResolver
+ *
+ * @description
+ * Set the culture for the error messages by loading an the correct culture resource file.
+ *
+ * @param {String} culture - The new culture in the format of 'en-gb' etc.
+ * @param {Function} cultureLoadingFn - A optional function to load the culture resolve which should
+ * return a promise which is resolved with the culture errorMessage object. If a function is not specified
+ * the culture file is loaded from the **i18nFileRootPath**.
+ * @returns {Promise} - A promise which is resolved with the loaded culture error messages object.
+ */
+ setCulture = function (culture, cultureLoadingFn) {
+ var defer = $q.defer();
+ cultureLoadingFn = cultureLoadingFn || loadRemoteCulture;
+ currentCulture = culture.toLowerCase();
+ if (angular.autoValidate.errorMessages[currentCulture] === undefined) {
+ cultureRetrievalPromise = cultureLoadingFn(culture);
+ cultureRetrievalPromise.then(function (response) {
+ cultureRetrievalPromise = undefined;
+ angular.autoValidate.errorMessages[currentCulture] = response.data;
+ defer.resolve(angular.autoValidate.errorMessages[currentCulture]);
+ }, function (err) {
+ angular.autoValidate.errorMessages[currentCulture] = {
+ defaultMsg: 'Loading culture failed!'
+ };
+ cultureRetrievalPromise = null;
+ defer.reject(err);
+ });
+ } else {
+ defer.resolve(angular.autoValidate.errorMessages[currentCulture]);
+ }
+
+ return defer.promise;
+ },
+
+ getErrorMessages = function (culture) {
+ var defer = $q.defer();
+ culture = culture === undefined ? currentCulture : culture.toLowerCase();
+ if (cultureRetrievalPromise !== undefined) {
+ cultureRetrievalPromise.then(function () {
+ defer.resolve(angular.autoValidate.errorMessages[culture]);
+ }, function (err) {
+ defer.reject(err);
+ });
+ } else {
+ defer.resolve(angular.autoValidate.errorMessages[culture]);
+ }
+ return defer.promise;
+ },
+
+ getMessageTypeOverride = function (errorType, el) {
+ var overrideKey;
+
+ if (el) {
+ // try and find an attribute which overrides the given error type in the form of errorType-err-type="someMsgKey"
+ errorType += '-err-type';
+
+
+ overrideKey = el.attr('ng-' + errorType);
+ if (overrideKey === undefined) {
+ overrideKey = el.attr('data-ng-' + errorType) || el.attr(errorType);
+ }
+
+ if (overrideKey) {
+ overrideKey = overrideKey.replace(/[\W]/g, '');
+ }
+ }
+
+ return overrideKey;
+ },
+
+ /**
+ * @ngdoc function
+ * @name defaultErrorMessageResolver#resolve
+ * @methodOf defaultErrorMessageResolver
+ *
+ * @description
+ * Resolves a validate error type into a user validation error message
+ *
+ * @param {String} errorType - The type of validation error that has occurred.
+ * @param {Element} el - The input element that is the source of the validation error.
+ * @returns {Promise} A promise that is resolved when the validation message has been produced.
+ */
+ resolve = function (errorType, el) {
+ var defer = $q.defer(),
+ errMsg,
+ parameters = [],
+ parameter,
+ messageTypeOverride;
+
+ if (cultureRetrievalPromise !== undefined) {
+ cultureRetrievalPromise.then(function () {
+ resolve(errorType, el).then(function (msg) {
+ defer.resolve(msg);
+ });
+ });
+ } else {
+ errMsg = angular.autoValidate.errorMessages[currentCulture][errorType];
+ messageTypeOverride = getMessageTypeOverride(errorType, el);
+ if (messageTypeOverride) {
+ errMsg = angular.autoValidate.errorMessages[currentCulture][messageTypeOverride];
+ }
+
+ if (errMsg === undefined && messageTypeOverride !== undefined) {
+ errMsg = angular.autoValidate.errorMessages[currentCulture].defaultMsg.format(messageTypeOverride);
+ } else if (errMsg === undefined) {
+ errMsg = angular.autoValidate.errorMessages[currentCulture].defaultMsg.format(errorType);
+ }
+
+ if (el && el.attr) {
+ try {
+ parameter = el.attr('ng-' + errorType);
+ if (parameter === undefined) {
+ parameter = el.attr('data-ng-' + errorType) || el.attr(errorType);
+ }
+
+ parameters.push(parameter || '');
+
+ errMsg = errMsg.format(parameters);
+ } catch (e) {}
+ }
+
+ defer.resolve(errMsg);
+ }
+
+ return defer.promise;
};
- angular.module('jcs-autoValidate')
- .factory('defaultErrorMessageResolver', [
- '$q',
- '$http',
- function ($q, $http) {
- var currentCulture = 'en-gb',
-
- i18nFileRootPath = 'js/angular-auto-validate/dist/lang',
-
- cultureRetrievalPromise,
-
- loadRemoteCulture = function (culture) {
- cultureRetrievalPromise = $http.get('{0}/jcs-auto-validate_{1}.json'.format(i18nFileRootPath, culture.toLowerCase()));
- return cultureRetrievalPromise;
- },
-
- /**
- * @ngdoc function
- * @name defaultErrorMessageResolver#setI18nFileRootPath
- * @methodOf defaultErrorMessageResolver
- *
- * @description
- * Set the root path to the il8n files on the server
- *
- * @param {String} rootPath - The root path on the server to the il8n file - this defaults
- * to 'js/angular-auto-validate/lang/'
- */
- setI18nFileRootPath = function (rootPath) {
- i18nFileRootPath = rootPath;
- },
-
- /**
- * @ngdoc function
- * @name defaultErrorMessageResolver#setCulture
- * @methodOf defaultErrorMessageResolver
- *
- * @description
- * Set the culture for the error messages by loading an the correct culture resource file.
- *
- * @param {String} culture - The new culture in the format of 'en-gb' etc.
- * @param {Function} cultureLoadingFn - A optional function to load the culture resolve which should
- * return a promise which is resolved with the culture errorMessage object. If a function is not specified
- * the culture file is loaded from the **i18nFileRootPath**.
- * @returns {Promise} - A promise which is resolved with the loaded culture error messages object.
- */
- setCulture = function (culture, cultureLoadingFn) {
- var defer = $q.defer();
- cultureLoadingFn = cultureLoadingFn || loadRemoteCulture;
- currentCulture = culture.toLowerCase();
- if (angular.autoValidate.errorMessages[currentCulture] === undefined) {
- cultureRetrievalPromise = cultureLoadingFn(culture);
- cultureRetrievalPromise.then(function (response) {
- cultureRetrievalPromise = undefined;
- angular.autoValidate.errorMessages[currentCulture] = response.data;
- defer.resolve(angular.autoValidate.errorMessages[currentCulture]);
- }, function (err) {
- angular.autoValidate.errorMessages[currentCulture] = {
- defaultMsg: 'Loading culture failed!'
- };
- cultureRetrievalPromise = null;
- defer.reject(err);
- });
- } else {
- defer.resolve(angular.autoValidate.errorMessages[currentCulture]);
- }
-
- return defer.promise;
- },
-
- getErrorMessages = function (culture) {
- var defer = $q.defer();
- culture = culture === undefined ? currentCulture : culture.toLowerCase();
- if (cultureRetrievalPromise !== undefined) {
- cultureRetrievalPromise.then(function () {
- defer.resolve(angular.autoValidate.errorMessages[culture]);
- }, function (err) {
- defer.reject(err);
- });
- } else {
- defer.resolve(angular.autoValidate.errorMessages[culture]);
- }
- return defer.promise;
- },
-
- getMessageTypeOverride = function (errorType, el) {
- var overrideKey;
-
- if (el) {
- // try and find an attribute which overrides the given error type in the form of errorType-err-type="someMsgKey"
- errorType += '-err-type';
-
- overrideKey = el.attr(errorType);
- if (overrideKey === undefined) {
- overrideKey = el.attr('data-ng-' + errorType) || el.attr('ng-' + errorType);
- }
- }
-
- return overrideKey;
- },
-
- /**
- * @ngdoc function
- * @name defaultErrorMessageResolver#resolve
- * @methodOf defaultErrorMessageResolver
- *
- * @description
- * Resolves a validate error type into a user validation error message
- *
- * @param {String} errorType - The type of validation error that has occurred.
- * @param {Element} el - The input element that is the source of the validation error.
- * @returns {Promise} A promise that is resolved when the validation message has been produced.
- */
- resolve = function (errorType, el) {
- var defer = $q.defer(),
- errMsg,
- parameters = [],
- parameter,
- messageTypeOverride;
-
- if (cultureRetrievalPromise !== undefined) {
- cultureRetrievalPromise.then(function () {
- resolve(errorType, el).then(function (msg) {
- defer.resolve(msg);
- });
- });
- } else {
- errMsg = angular.autoValidate.errorMessages[currentCulture][errorType];
- messageTypeOverride = getMessageTypeOverride(errorType, el);
- if (messageTypeOverride) {
- errMsg = angular.autoValidate.errorMessages[currentCulture][messageTypeOverride];
- }
-
- if (errMsg === undefined) {
- errMsg = angular.autoValidate.errorMessages[currentCulture].defaultMsg.format(errorType);
- }
-
- if (el && el.attr) {
- try {
- parameter = el.attr(errorType);
- if (parameter === undefined) {
- parameter = el.attr('data-ng-' + errorType) || el.attr('ng-' + errorType);
- }
-
- parameters.push(parameter || '');
-
- errMsg = errMsg.format(parameters);
- } catch (e) {}
- }
-
- defer.resolve(errMsg);
- }
-
- return defer.promise;
- };
-
- return {
- setI18nFileRootPath: setI18nFileRootPath,
- setCulture: setCulture,
- getErrorMessages: getErrorMessages,
- resolve: resolve
- };
+ return {
+ setI18nFileRootPath: setI18nFileRootPath,
+ setCulture: setCulture,
+ getErrorMessages: getErrorMessages,
+ resolve: resolve
+ };
+}
+
+DefaultErrorMessageResolverFn.$inject = [
+ '$q',
+ '$http'
+];
+
+angular.module('jcs-autoValidate').factory('defaultErrorMessageResolver', DefaultErrorMessageResolverFn);
+
+function foundation6ElementModifierFn() {
+ var reset = function (el, inputEl) {
+ angular.forEach(el.find('small'), function (smallEl) {
+ if (angular.element(smallEl).hasClass('form-error is-visible')) {
+ angular.element(smallEl).remove();
+ }
+ });
+
+ inputEl.removeClass('alert callout');
+ },
+ findParentColumn = function (el) {
+ var parent = el;
+ for (var i = 0; i <= 3; i += 1) {
+ if (parent !== undefined && (parent.hasClass('columns') || parent.hasClass('column'))) {
+ break;
+ } else if (parent !== undefined) {
+ parent = parent.parent();
+ }
+ }
+
+ return parent;
+ },
+
+ /**
+ * @ngdoc function
+ * @name foundation6ElementModifier#makeValid
+ * @methodOf foundation6ElementModifier
+ *
+ * @description
+ * Makes an element appear valid by apply Foundation 6 specific styles and child elements.
+ * See: http://foundation.zurb.com/sites/docs/forms.html
+ *
+ * @param {Element} el - The input control element that is the target of the validation.
+ */
+ makeValid = function (el) {
+ var parentColumn = findParentColumn(el);
+ reset(parentColumn && parentColumn.length > 0 ? parentColumn : el, el);
+ },
+
+ /**
+ * @ngdoc function
+ * @name foundation6ElementModifier#makeInvalid
+ * @methodOf foundation6ElementModifier
+ *
+ * @description
+ * Makes an element appear invalid by apply Foundation 6 specific styles and child elements.
+ * See: http://foundation.zurb.com/sites/docs/forms.html
+ *
+ * @param {Element} el - The input control element that is the target of the validation.
+ */
+ makeInvalid = function (el, errorMsg) {
+ var parentColumn = findParentColumn(el),
+ helpTextEl;
+ reset(parentColumn || el, el);
+ el.addClass('alert callout');
+ if (parentColumn) {
+ helpTextEl = angular.element('' + errorMsg + '');
+ parentColumn.append(helpTextEl);
+ }
+ },
+
+ /**
+ * @ngdoc function
+ * @name foundation6ElementModifier#makeDefault
+ * @methodOf foundation6ElementModifier
+ *
+ * @description
+ * Makes an element appear in its default visual state by apply Foundation 6 specific styles and child elements.
+ *
+ * @param {Element} el - The input control element that is the target of the validation.
+ */
+ makeDefault = function (el) {
+ makeValid(el);
+ };
+
+ return {
+ makeValid: makeValid,
+ makeInvalid: makeInvalid,
+ makeDefault: makeDefault,
+ key: 'foundation6'
+ };
+}
+
+angular.module('jcs-autoValidate').factory('foundation6ElementModifier', foundation6ElementModifierFn);
+
+function ElementUtilsFn() {
+ var isElementVisible = function (el) {
+ return el[0].offsetWidth > 0 && el[0].offsetHeight > 0;
+ };
+
+ return {
+ isElementVisible: isElementVisible
+ };
+}
+
+function ValidationManagerFn(validator, elementUtils, $anchorScroll) {
+ var elementTypesToValidate = ['input', 'textarea', 'select', 'form'],
+
+ elementIsVisible = function (el) {
+ return elementUtils.isElementVisible(el);
+ },
+
+ getFormOptions = function (el) {
+ var frmCtrl = angular.element(el).controller('form'),
+ options;
+
+ if (frmCtrl !== undefined && frmCtrl !== null) {
+ options = frmCtrl.autoValidateFormOptions;
+ } else {
+ options = validator.defaultFormValidationOptions;
+ }
+
+ return options;
+ },
+
+ /**
+ * Only validate if the element is present, it is visible, if it is not a comment,
+ * it is either a valid user input control (input, select, textare, form) or
+ * it is a custom control register by the developer.
+ * @param el
+ * @param formOptions The validation options of the parent form
+ * @returns {boolean} true to indicate it should be validated
+ */
+ shouldValidateElement = function (el, formOptions, formSubmitted) {
+ var elementExists = el && el.length > 0,
+ isElementAComment = elementExists && el[0].nodeName.toLowerCase() === '#comment',
+ correctVisibilityToValidate,
+ correctTypeToValidate,
+ correctPhaseToValidate;
+
+ if (elementExists && isElementAComment === false) {
+ correctVisibilityToValidate = elementIsVisible(el) || formOptions.validateNonVisibleControls;
+ correctTypeToValidate = elementTypesToValidate.indexOf(el[0].nodeName.toLowerCase()) > -1 ||
+ el[0].hasAttribute('register-custom-form-control');
+ correctPhaseToValidate = formOptions.validateOnFormSubmit === false ||
+ (formOptions.validateOnFormSubmit === true && formSubmitted === true);
+ }
+
+ return elementExists && !isElementAComment && correctVisibilityToValidate && correctTypeToValidate && correctPhaseToValidate;
+
+ },
+
+ /**
+ * @ngdoc validateElement
+ * @name validation#validateElement
+ * @param {object} modelCtrl holds the information about the element e.g. $invalid, $valid
+ * @param {options}
+ * - forceValidation if set to true forces the validation even if the element is pristine
+ * - disabled if set to true forces the validation is disabled and will return true
+ * - validateNonVisibleControls if set to true forces the validation of non visible element i.e. display:block
+ * @description
+ * Validate the form element and make invalid/valid element model status.
+ *
+ * As of v1.17.22:
+ * BREAKING CHANGE to validateElement on the validationManger. The third parameter is now the parent form's
+ * autoValidateFormOptions object on the form controller. This can be left blank and will be found by the
+ * validationManager.
+ */
+ validateElement = function (modelCtrl, el, options) {
+ var isValid = true,
+ frmOptions = options || getFormOptions(el),
+ needsValidation = modelCtrl.$pristine === false || frmOptions.forceValidation,
+ errorType,
+ findErrorType = function ($errors) {
+ var keepGoing = true,
+ errorTypeToReturn;
+ angular.forEach($errors, function (status, errortype) {
+ if (keepGoing && status) {
+ keepGoing = false;
+ errorTypeToReturn = errortype;
}
- ]);
-}(String, angular));
+ });
-(function (angular) {
- 'use strict';
+ return errorTypeToReturn;
+ };
- angular.module('jcs-autoValidate')
- .factory('foundation5ElementModifier', [
-
- function () {
- var reset = function (el, inputEl) {
- angular.forEach(el.find('small'), function (smallEl) {
- if (angular.element(smallEl).hasClass('error')) {
- angular.element(smallEl).remove();
- }
- });
-
- inputEl.removeClass('error');
- },
- findParentColumn = function (el) {
- var parent = el;
- for (var i = 0; i <= 3; i += 1) {
- if (parent !== undefined && parent.hasClass('columns')) {
- break;
- } else if (parent !== undefined) {
- parent = parent.parent();
- }
- }
-
- return parent;
- },
-
- /**
- * @ngdoc function
- * @name foundation5ElementModifier#makeValid
- * @methodOf foundation5ElementModifier
- *
- * @description
- * Makes an element appear valid by apply Foundation 5 specific styles and child elements.
- * See: http://foundation.zurb.com/docs/components/forms.html
- *
- * @param {Element} el - The input control element that is the target of the validation.
- */
- makeValid = function (el) {
- var parentColumn = findParentColumn(el);
- reset(parentColumn && parentColumn.length > 0 ? parentColumn : el, el);
- },
-
- /**
- * @ngdoc function
- * @name foundation5ElementModifier#makeInvalid
- * @methodOf foundation5ElementModifier
- *
- * @description
- * Makes an element appear invalid by apply Foundation 5 specific styles and child elements.
- * See: http://foundation.zurb.com/docs/components/forms.html
- *
- * @param {Element} el - The input control element that is the target of the validation.
- */
- makeInvalid = function (el, errorMsg) {
- var parentColumn = findParentColumn(el),
- helpTextEl;
- reset(parentColumn || el, el);
- el.addClass('error');
- if (parentColumn) {
- helpTextEl = angular.element('' + errorMsg + '');
- parentColumn.append(helpTextEl);
- }
- },
-
- /**
- * @ngdoc function
- * @name foundation5ElementModifier#makeDefault
- * @methodOf foundation5ElementModifier
- *
- * @description
- * Makes an element appear in its default visual state by apply foundation 5 specific styles and child elements.
- *
- * @param {Element} el - The input control element that is the target of the validation.
- */
- makeDefault = function (el) {
- makeValid(el);
- };
-
- return {
- makeValid: makeValid,
- makeInvalid: makeInvalid,
- makeDefault: makeDefault,
- key: 'foundation5'
- };
+ if (frmOptions.disabled === false) {
+ if ((frmOptions.forceValidation ||
+ (shouldValidateElement(el, frmOptions, frmOptions.getFormController().$submitted) &&
+ modelCtrl &&
+ needsValidation))) {
+ isValid = !modelCtrl.$invalid;
+
+ if (frmOptions.removeExternalValidationErrorsOnSubmit && modelCtrl.removeAllExternalValidation) {
+ modelCtrl.removeAllExternalValidation();
+ }
+
+ if (modelCtrl.$pending !== undefined && options.waitForAsyncValidators === true) {
+ // we have pending async validators
+ validator.waitForAsyncValidators(el);
+ } else {
+ if (isValid) {
+ validator.makeValid(el);
+ } else {
+ errorType = findErrorType(modelCtrl.$errors || modelCtrl.$error);
+ if (errorType === undefined) {
+ // we have a weird situation some users are encountering where a custom control
+ // is valid but the ngModel is report it isn't and thus no valid error type can be found
+ isValid = true;
+ } else {
+ validator.getErrorMessage(errorType, el).then(function (errorMsg) {
+ validator.makeInvalid(el, errorMsg);
+ });
+ }
+ }
+ }
+ }
+ }
+
+ return isValid;
+ },
+
+ resetElement = function (element) {
+ validator.makeDefault(element);
+ },
+
+ resetForm = function (frmElement) {
+ angular.forEach((frmElement[0].all || frmElement[0].elements) || frmElement[0], function (element) {
+ var controller,
+ ctrlElement = angular.element(element);
+ controller = ctrlElement.controller('ngModel');
+
+ if (controller !== undefined) {
+ if (ctrlElement[0].nodeName.toLowerCase() === 'form') {
+ // we probably have a sub form
+ resetForm(ctrlElement);
+ } else {
+ controller.$setPristine();
+ }
+ }
+ });
+ },
+
+ validateForm = function (frmElement) {
+ var frmValid = true,
+ frmCtrl = frmElement ? angular.element(frmElement).controller('form') : undefined,
+ processElement = function (ctrlElement, force, formOptions) {
+ var controller, isValid, ctrlFormOptions, originalForceValue;
+
+ ctrlElement = angular.element(ctrlElement);
+ controller = ctrlElement.controller('ngModel');
+
+ if (controller !== undefined && (force || shouldValidateElement(ctrlElement, formOptions, frmCtrl.$submitted))) {
+ if (ctrlElement[0].nodeName.toLowerCase() === 'form') {
+ // we probably have a sub form
+ validateForm(ctrlElement);
+ } else {
+ // we need to get the options for the element rather than use the passed in as the
+ // element could be an ng-form and have different options to the parent form.
+ ctrlFormOptions = getFormOptions(ctrlElement);
+ originalForceValue = ctrlFormOptions.forceValidation;
+ ctrlFormOptions.forceValidation = force;
+ try {
+ isValid = validateElement(controller, ctrlElement, ctrlFormOptions);
+ if (validator.firstInvalidElementScrollingOnSubmitEnabled() && !isValid && frmValid) {
+ var ctrlElementId = ctrlElement.attr('id');
+ if (ctrlElementId) {
+ $anchorScroll(ctrlElementId);
+ }
+ }
+ frmValid = frmValid && isValid;
+ } finally {
+ ctrlFormOptions.forceValidation = originalForceValue;
+ }
}
- ]);
-}(angular));
+ }
+ },
+ clonedOptions;
+
+ if (frmElement === undefined || (frmCtrl !== undefined && frmCtrl.autoValidateFormOptions.disabled)) {
+ return frmElement !== undefined;
+ }
+
+ //force the validation of controls
+ clonedOptions = angular.copy(frmCtrl.autoValidateFormOptions);
+ clonedOptions.forceValidation = true;
+
+ // IE8 holds the child controls collection in the all property
+ // Firefox in the elements and chrome as a child iterator
+ angular.forEach((frmElement[0].elements || frmElement[0].all) || frmElement[0], function (ctrlElement) {
+ processElement(ctrlElement, true, clonedOptions);
+ });
+
+ // If you have a custom form control that should be validated i.e.
+ // if you are using Foundation 5 you will need to set the Foundation 5 element modifier as the default one
+if you are using Foundation 6 you will need to set the Foundation 6 element modifier as the default one
angular.module('my-app')
.run([
'validator',
- 'foundation5ElementModifier',
- function (validator, foundation5ElementModifier) {
- validator.setDefaultElementModifier(foundation5ElementModifier.key);
+ 'Foundation6ElementModifier',
+ function (validator, Foundation6ElementModifier) {
+ validator.setDefaultElementModifier(Foundation6ElementModifier.key);
}]);
- If you are not using Bootstrap3 or Foundation5 you will need to create a custom element modifier so see the below section
+If you are not using Bootstrap3 or Foundation6 you will need to create a custom element modifier so see the below section
Now that you are using auto-validate you haven't got to worry about putting your error messages in you html @@ -414,7 +414,7 @@
If you are not using Bootstrap3 or Foundation5 CSS libraries you will need to create a custom element modifier +
If you are not using Bootstrap3 or Foundation6 CSS libraries you will need to create a custom element modifier which takes care of updating the visual state of an element, don't worry this is really easy! You can see a few example of what to put in them here and here.
angular.module('my-app')