diff --git a/app.js b/app.js index e757f50..98e923d 100644 --- a/app.js +++ b/app.js @@ -37,7 +37,7 @@ myApp.controller('Ctrl', ['$location', '$route', '$scope', '$translate', functio // -- Controller to use Angular-Validation Directive // ----------------------------------------------- -myApp.controller('CtrlValidationDirective', ['$scope', 'validationService', function ($scope, validationService) { +myApp.controller('CtrlValidationDirective', ['$q', '$scope', 'validationService', function ($q, $scope, validationService) { $scope.$validationOptions = { debounce: 1500 }; // you can change default debounce globally $scope.submitForm = function() { @@ -48,6 +48,20 @@ myApp.controller('CtrlValidationDirective', ['$scope', 'validationService', func $scope.showValidationSummary = function () { $scope.displayValidationSummary = true; } + $scope.customRemoteValidationCall = function() { + var deferred = $q.defer(); + setTimeout(function() { + var isValid = ($scope.input1 === "abc") ? true : false; + + // you can return a boolean for isValid + //deferred.resolve(isValid); + + // or you can return an object as { isValid: bool, message: msg } + deferred.resolve({ isValid: isValid, message: 'Returned error from promise.'}); + }, 1000); + + return deferred.promise; + } }]); // -- Controller to use Angular-Validation Directive with 2 forms @@ -67,18 +81,18 @@ myApp.controller('Ctrl2forms', ['$scope', 'validationService', function ($scope, // ----------------------------------------------- // exact same testing form used except that all validators are programmatically added inside controller via Angular-Validation Service -myApp.controller('CtrlValidationService', ['$scope', '$translate', 'validationService', function ($scope, $translate, validationService) { +myApp.controller('CtrlValidationService', ['$q', '$scope', '$translate', 'validationService', function ($q, $scope, $translate, validationService) { // start by creating the service var myValidation = new validationService(); // you can create indepent call to the validation service // also below the multiple properties available myValidation.addValidator({ - elmName: 'input2', + elmName: 'input1', // friendlyName: $translate.instant('FIRST_NAME'), - debounce: 3000, + debounce: 1000, scope: $scope, - rules: 'numeric_signed|required' + rules: 'alpha|min_len:2|remote:customRemoteValidationCall|required' }); // you can also chain validation service and add multiple validators at once @@ -90,6 +104,7 @@ myApp.controller('CtrlValidationService', ['$scope', '$translate', 'validationSe // the available object properties are the exact same set as the directive except that they are camelCase myValidation .setGlobalOptions({ debounce: 1500, scope: $scope }) + .addValidator({ elmName: 'input2', debounce: 3000, rules: 'numeric_signed|required'}) .addValidator('input3', 'float_signed|between_num:-0.6,99.5|required') .addValidator('input4', 'exact_len:4|regex:YYWW:=^(0[9]|1[0-9]|2[0-9]|3[0-9])(5[0-2]|[0-4][0-9])$:regex|required|integer') .addValidator('input5', 'email|required|min_len:6', $translate.instant('INPUT5')) // 3rd argument being the Friendly name @@ -125,6 +140,15 @@ myApp.controller('CtrlValidationService', ['$scope', '$translate', 'validationSe alert('All good, proceed with submit...'); } } + $scope.customRemoteValidationCall = function() { + var deferred = $q.defer(); + setTimeout(function() { + var isValid = ($scope.input1 === "abc") ? true : false; + deferred.resolve({ isValid: isValid, message: 'Returned error from promise.'}); + }, 1000); + + return deferred.promise; + } }]); // -- Controller to use Angular-Validation with Directive and ngRepeat diff --git a/bower.json b/bower.json index 4b04f95..4acfb68 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-validation-ghiscoding", - "version": "1.3.24", + "version": "1.3.25", "author": "Ghislain B.", "description": "Angular-Validation Directive and Service (ghiscoding)", "main": [ @@ -18,11 +18,13 @@ "license": "MIT", "ignore": [ "**/.*", + "full-tests", "node_modules", "bower_components", "test", "tests", "more-examples", + "protractor", "templates", "app.js", "changelog.txt", diff --git a/changelog.txt b/changelog.txt index d5f8dc7..aebea6b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -25,4 +25,5 @@ Angular-Validation change logs 1.3.21 (2015-04-29) Moved the Alternate Text inside the $translate promise as well which removes possible delay of non-translated text appearing as alternate text (this will not affect regular text, or already translated text). Also cleanup code and made my Gulp task even more automated. 1.3.22 (2015-05-03) Added new element attribute of `friendly-name` which is used ONLY in the ValidationSummary, this friendly name is to give a better element name display, which also support translation, inside the ValidationSummary instead of just "input1" (see ValidationSummary for more details). 1.3.23 (2015-05-05) Added option to display only last error message instead of all messages at once. Fixed a bug where changing route on View/Controller would make the ValidationSummary fail when coming back to original View/Controller, this bug was associated to the fact that the ValidationSummary kept growing from Controller to Controller, now this ValidationSummary is wipe out as soon as we detect a route change. -1.3.24 (2015-05-17) Replaced all `:param` inside each locale translations with a better standard of {0}, {1}, etc.. like C# `String.Format()`. Added a full Protractor End-to-End test suite (1000+ asserts). Fixed a few minor bugs found with Protractor test cases. Fixed issue #36, bower.json scripts in wrong order. \ No newline at end of file +1.3.24 (2015-05-17) Replaced all `:param` inside each locale translations with a better standard of {0}, {1}, etc.. like C# `String.Format()`. Added a full Protractor End-to-End test suite (1000+ asserts). Fixed a few minor bugs found with Protractor test cases. Fixed issue #36, bower.json scripts in wrong order. +1.3.25 (2015-05-19) Enhancement #34 to add Remote Validation and updated Protractor to cover this new feature. \ No newline at end of file diff --git a/dist/angular-validation.min.js b/dist/angular-validation.min.js index f8ab213..dd85e26 100644 --- a/dist/angular-validation.min.js +++ b/dist/angular-validation.min.js @@ -2,11 +2,11 @@ * Angular-Validation Directive and Service (ghiscoding) * http://github.com/ghiscoding/angular-validation * @author: Ghislain B. - * @version: 1.3.24 + * @version: 1.3.25 * @license: MIT - * @build: Sun May 17 2015 22:37:50 GMT-0400 (Eastern Daylight Time) + * @build: Tue May 19 2015 17:03:51 GMT-0400 (Eastern Daylight Time) */ angular.module("ghiscoding.validation",["pascalprecht.translate"]).directive("validation",["$timeout","validationCommon","validationRules",function(i,t){return{restrict:"A",require:"ngModel",link:function(a,e,n,d){function l(){v=!0,i.cancel(r),s.updateErrorMsg(""),d.$setValidity("validation",!0),"undefined"!=typeof u&&e.unbind("blur",u)}function o(t){return s.validate(t,!1),s.isFieldRequired()||""!==t&&null!==t&&"undefined"!=typeof t?(v=!1,(t||s.isFieldRequired())&&d.$setValidity("validation",!1),e.bind("blur",u=function(){v||a.$evalAsync(d.$setValidity("validation",s.validate(t,!0)))}),""!==t&&"undefined"!=typeof t||"NUMBER"!==e.prop("type").toUpperCase()?"SELECT"===e.prop("tagName").toUpperCase()?(d.$setValidity("validation",s.validate(t,!0)),t):("undefined"!=typeof t&&(s.updateErrorMsg(""),i.cancel(r),r=i(function(){a.$evalAsync(d.$setValidity("validation",s.validate(t,!0)))},s.typingLimit)),t):(i.cancel(r),d.$setValidity("validation",s.validate(t,!0)),t)):(l(),t)}var r,u,s=new t(a,e,n,d),v=!1;d.$formatters.unshift(o),d.$parsers.unshift(o),n.$observe("disabled",function(i){i?d.$setValidity("validation",!0):d.$setValidity("validation",s.validate(d.$viewValue,!0))})}}}]); -angular.module("ghiscoding.validation").factory("validationCommon",["$rootScope","$timeout","$translate","validationRules",function(t,e,a,r){function i(){var t=this,e={};t.validators=[],t.typingLimit=F,t.validatorAttrs.hasOwnProperty("debounce")?t.typingLimit=parseInt(t.validatorAttrs.debounce,10):t.validatorAttrs.hasOwnProperty("typingLimit")?t.typingLimit=parseInt(t.validatorAttrs.typingLimit,10):t.scope.$validationOptions&&t.scope.$validationOptions.hasOwnProperty("debounce")&&(t.typingLimit=parseInt(t.scope.$validationOptions.debounce,10));var a=t.validatorAttrs.hasOwnProperty("rules")?t.validatorAttrs.rules:t.validatorAttrs.validation;if(a.indexOf("regex:")>=0){var i=a.match("regex:(.*?):regex");if(i.length<2)throw'Regex validator within the validation needs to be define with an opening "regex:" and a closing ":regex", please review your validator.';var n=i[1].split(":=");e={message:n[0],pattern:n[1]},a=a.replace(i[0],"regex:")}var s=a.split("|");if(s){t.bFieldRequired=a.indexOf("required")>=0?!0:!1;for(var l=0,o=s.length;o>l;l++){var d=s[l].split(":"),u=s[l].indexOf("alt=")>=0?!0:!1;t.validators[l]=r.getElementValidators({altText:u===!0?2===d.length?d[1]:d[2]:"",customRegEx:e,rule:d[0],ruleParams:u&&2===d.length?null:d[1]})}}return t}function n(t){return y(U,"fieldName",t)}function s(){return U}function l(t,e,a,r){this.scope=t,this.elm=e,this.ctrl=r,this.validatorAttrs=a,f(e,a,r,t),this.defineValidation()}function o(){var t=this;return t.bFieldRequired}function d(t){var e=A(U,"fieldName",t);e>=0&&U.splice(e,1)}function u(t,e){var a=A(t,"field",e);a>=0&&t.splice(a,1),a=A(L,"field",e),a>=0&&L.splice(a,1)}function p(t){w=t}function m(t){$=t}function c(t,e){var r=this;e&&e.obj&&(r=e.obj,r.validatorAttrs=e.obj.attrs);var i=e&&e.elm?e.elm:r.elm,n=i&&i.attr("name")?i.attr("name"):null;if("undefined"==typeof n||null===n)throw'Angular-Validation Service requires you to have a (name="") attribute on the element to validate... Your element is: ng-model="'+i.attr("ng-model")+'"';var s=e&&e.translate?a.instant(t):t,l=n.replace(/[|&;$%@"<>()+,\[\]\{\}]/g,""),o=null;if(r.validatorAttrs&&r.validatorAttrs.hasOwnProperty("validationErrorTo")){var d=r.validatorAttrs.validationErrorTo.charAt(0),u="."===d||"#"===d?r.validatorAttrs.validationErrorTo:"#"+r.validatorAttrs.validationErrorTo;o=angular.element(document.querySelector(u))}o&&0!==o.length||(o=angular.element(document.querySelector(".validation-"+l)));var p=e&&e.isSubmitted?e.isSubmitted:!1;e&&!e.isValid&&(p||r.ctrl.$dirty||r.ctrl.$touched)?o.length>0?o.text(s):i.after(''+s+""):o.text("")}function g(t,e){var r,i,s=this,l=!0,o=!0,d="";"undefined"==typeof t&&(t="");for(var u=s.validatorAttrs&&s.validatorAttrs.name?s.validatorAttrs.name:s.attrs&&s.attrs.name?s.attrs.name:s.elm.attr("name"),p=n(u),m=s.validatorAttrs.hasOwnProperty("rules")?s.validatorAttrs.rules:s.validatorAttrs.validation,c=0,g=s.validators.length;g>c;c++){if(i=s.validators[c],"conditionalDate"===i.type){if(r=new RegExp(i.pattern,"i"),l=("\\S+"===i.pattern||m&&"required"===i.pattern)&&null===t?!1:r.test(t)){var f=i.dateType,y=S(t,f).getTime();if(2==i.params.length){var b=S(i.params[0],f).getTime(),A=S(i.params[1],f).getTime(),O=R(i.condition[0],y,b),E=R(i.condition[1],y,A);l=O&&E?!0:!1}else{var x=S(i.params[0],f).getTime();l=R(i.condition,y,x)}}}else if("conditionalNumber"===i.type)if(2==i.params.length){var O=R(i.condition[0],parseFloat(t),parseFloat(i.params[0])),E=R(i.condition[1],parseFloat(t),parseFloat(i.params[1]));l=O&&E?!0:!1}else l=R(i.condition,parseFloat(t),parseFloat(i.params[0]));else if("match"===i.type){var N=i.params[0],T=s.scope.$eval(N);l=T===t&&!!t}else s.elm.prop("disabled")||1==parseInt(s.elm.attr("ng-disabled"))||"true"===s.elm.attr("ng-disabled")?l=!0:"string"==typeof t&&""===t&&"NUMBER"===s.elm.prop("type").toUpperCase()?l=!1:(r=new RegExp(i.pattern,"i"),l=("\\S+"===i.pattern||m&&"required"===i.pattern)&&null===t?!1:r.test(t));(!s.bFieldRequired&&!t||s.elm.prop("disabled")||1==parseInt(s.elm.attr("ng-disabled"))||"true"===s.elm.attr("ng-disabled"))&&(l=!0),l||(o=!1,function(t,r,i){var n=i.message;i.altText&&i.altText.length>0&&(n=i.altText.replace("alt=","")),a(n).then(function(a){d.length>0&&$?d=" "+(i&&i.params?String.format(a,i.params):a):d+=" "+(i&&i.params?String.format(a,i.params):a),v(s,t,d,o,e)})["catch"](function(){i.altText&&i.altText.length>0&&(d.length>0&&$?d=" "+n:d+=" "+n,v(s,t,d,o,e))})}(p,l,i))}return l&&(h(s,""),s.updateErrorMsg("",{isValid:l})),p&&(p.isValid=o,o&&(p.message="")),o}function f(t,e,r,i){var n=e.name?e.name:t.attr("name"),s=e&&e.friendlyName?a.instant(e.friendlyName):"",l={fieldName:n,friendlyName:s,elm:t,attrs:e,ctrl:r,scope:i,isValid:!1,message:""},o=A(U,"fieldName",t.attr("name"));return o>=0?U[o]=l:U.push(l),U}function v(t,e,a,r,i){a=a.trim(),h(e,a),e&&(e.message=a),i&&!e.isValid?t.updateErrorMsg(a,{isValid:r}):e&&e.isValid&&h(e,"")}function h(t,e){var r=t.validatorAttrs&&t.validatorAttrs.name?t.validatorAttrs.name:t.attrs&&t.attrs.name?t.attrs.name:t.elm.attr("name"),i=O(r,t),n=A(L,"field",r);if(n>=0&&""===e)L.splice(n,1);else if(""!==e){var s=t.attrs&&t.friendlyName?a.instant(t.friendlyName):"",l={field:r,friendlyName:s,message:e,formName:i?i.$name:null};n>=0?L[n]=l:L.push(l)}return t.scope.$validationSummary=L,i&&(i.$validationSummary=b(L,"formName",i.$name)),L}function y(t,e,a){for(var r=0;r8?t.substring(9).split(":"):null;break;case"UK":case"EURO":case"EURO_SHORT":case"EURO-SHORT":case"EUROPE":a=t.substring(0,8),r=t.substring(2,3),i=E(a,r),o=i[0],l=i[1],s=parseInt(i[2])<50?"20"+i[2]:"19"+i[2],n=t.length>8?t.substring(9).split(":"):null;break;case"US_LONG":case"US-LONG":a=t.substring(0,10),r=t.substring(2,3),i=E(a,r),l=i[0],o=i[1],s=i[2],n=t.length>8?t.substring(9).split(":"):null;break;case"US":case"US_SHORT":case"US-SHORT":a=t.substring(0,8),r=t.substring(2,3),i=E(a,r),l=i[0],o=i[1],s=parseInt(i[2])<50?"20"+i[2]:"19"+i[2],n=t.length>8?t.substring(9).split(":"):null;break;case"ISO":default:a=t.substring(0,10),r=t.substring(4,5),i=E(a,r),s=i[0],l=i[1],o=i[2],n=t.length>10?t.substring(11).split(":"):null}var d=n&&3===n.length?n[0]:0,u=n&&3===n.length?n[1]:0,p=n&&3===n.length?n[2]:0;return new Date(s,l-1,o,d,u,p)}function E(t,e){var a=[];switch(e){case"/":a=t.split("/");break;case".":a=t.split(".");break;case"-":default:a=t.split("-")}return a}function R(t,e,a){var r=!1;switch(t){case"<":r=a>e?!0:!1;break;case"<=":r=a>=e?!0:!1;break;case">":r=e>a?!0:!1;break;case">=":r=e>=a?!0:!1;break;case"!=":case"<>":r=e!=a?!0:!1;break;case"=":case"==":r=e==a?!0:!1;break;default:r=!1}return r}function x(){return this.replace(/^\s+|\s+$/g,"")}function N(){var t=Array.isArray(arguments[0])?arguments[0]:arguments;return this.replace(/{(\d+)}/g,function(e,a){return"undefined"!=typeof t[a]?t[a]:e})}function T(t){var e=Array.isArray(arguments[1])?arguments[1]:Array.prototype.slice.call(arguments,1);return t.replace(/{(\d+)}/g,function(t,a){return"undefined"!=typeof e[a]?e[a]:t})}var w=!1,$=!1,F=1e3,U=[],L=[];t.$on("$routeChangeStart",function(){w||($=!1,U=[],L=[])});var V=function(t,e,a,r){this.timer=null,this.bFieldRequired=!1,this.validators=[],this.typingLimit=F,this.scope=t,this.elm=e,this.ctrl=r,this.validatorAttrs=a,t&&e&&a&&r&&(f(e,a,r,t),this.defineValidation())};return V.prototype.defineValidation=i,V.prototype.getFormElementByName=n,V.prototype.getFormElements=s,V.prototype.isFieldRequired=o,V.prototype.initialize=l,V.prototype.removeFromValidationSummary=u,V.prototype.removeFromFormElementObjectList=d,V.prototype.setBypassRootScopeReset=p,V.prototype.setDisplayOnlyLastErrorMsg=m,V.prototype.updateErrorMsg=c,V.prototype.validate=g,String.prototype.trim=x,String.prototype.format=N,String.format=T,V}]); -angular.module("ghiscoding.validation").factory("validationRules",[function(){function e(e){var a="undefined"!=typeof e.altText?e.altText.replace("alt=",""):null,t=e.hasOwnProperty("customRegEx")?e.customRegEx:null,s=e.hasOwnProperty("rule")?e.rule:null,r=e.hasOwnProperty("ruleParams")?e.ruleParams:null,n={};switch(s){case"alpha":n={pattern:"^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ])+$",message:"INVALID_ALPHA",type:"regex"};break;case"alphaSpaces":case"alpha_spaces":n={pattern:"^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ\\s])+$",message:"INVALID_ALPHA_SPACE",type:"regex"};break;case"alphaNum":case"alpha_num":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ])+$",message:"INVALID_ALPHA_NUM",type:"regex"};break;case"alphaNumSpaces":case"alpha_num_spaces":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ\\s])+$",message:"INVALID_ALPHA_NUM_SPACE",type:"regex"};break;case"alphaDash":case"alpha_dash":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ_-])+$",message:"INVALID_ALPHA_DASH",type:"regex"};break;case"alphaDashSpaces":case"alpha_dash_spaces":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ\\s_-])+$",message:"INVALID_ALPHA_DASH_SPACE",type:"regex"};break;case"betweenLen":case"between_len":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_len:1,5";n={pattern:"^.{"+_[0]+","+_[1]+"}$",message:"INVALID_BETWEEN_CHAR",params:[_[0],_[1]],type:"regex"};break;case"betweenNum":case"between_num":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_num:1,5";n={condition:[">=","<="],message:"INVALID_BETWEEN_NUM",params:[_[0],_[1]],type:"conditionalNumber"};break;case"boolean":n={pattern:"^(true|True|false|False|0|1)$",message:"INVALID_BOOLEAN",type:"regex"};break;case"checked":n={pattern:"^true$",message:"INVALID_CHECKBOX_SELECTED",type:"regex"};break;case"creditCard":case"credit_card":n={pattern:"^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\\d{3})\\d{11})$",message:"INVALID_CREDIT_CARD",type:"regex"};break;case"dateEuroLong":case"date_euro_long":n={pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG",type:"regex"};break;case"dateEuroLongBetween":case"date_euro_long_between":case"betweenDateEuroLong":case"between_date_euro_long":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_long:01-01-1990,31-12-2015";n={condition:[">=","<="],dateType:"EURO_LONG",params:[_[0],_[1]],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG_BETWEEN",type:"conditionalDate"};break;case"dateEuroLongMax":case"date_euro_long_max":case"maxDateEuroLong":case"max_date_euro_long":n={condition:"<=",dateType:"EURO_LONG",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG_MAX",type:"conditionalDate"};break;case"dateEuroLongMin":case"date_euro_long_min":case"minDateEuroLong":case"min_date_euro_long":n={condition:">=",dateType:"EURO_LONG",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG_MIN",type:"conditionalDate"};break;case"dateEuroShort":case"date_euro_short":n={pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT",type:"regex"};break;case"dateEuroShortBetween":case"date_euro_short_between":case"betweenDateEuroShort":case"between_date_euro_short":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_short:01-01-90,31-12-15";n={condition:[">=","<="],dateType:"EURO_SHORT",params:[_[0],_[1]],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateEuroShortMax":case"date_euro_short_max":case"maxDateEuroShort":case"max_date_euro_short":n={condition:"<=",dateType:"EURO_SHORT",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT_MAX",type:"conditionalDate"};break;case"dateEuroShortMin":case"date_euro_short_min":case"minDateEuroShort":case"min_date_euro_short":n={condition:">=",dateType:"EURO_SHORT",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT_MIN",type:"conditionalDate"};break;case"dateIso":case"date_iso":n={pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO",type:"regex"};break;case"dateIsoBetween":case"date_iso_between":case"betweenDateIso":case"between_date_iso":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_iso:1990-01-01,2000-12-31";n={condition:[">=","<="],dateType:"ISO",params:[_[0],_[1]],pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO_BETWEEN",type:"conditionalDate"};break;case"dateIsoMax":case"date_iso_max":case"maxDateIso":case"max_date_iso":n={condition:"<=",dateType:"ISO",params:[r],pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO_MAX",type:"conditionalDate"};break;case"dateIsoMin":case"date_iso_min":case"minDateIso":case"min_date_iso":n={condition:">=",dateType:"ISO",params:[r],pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO_MIN",type:"conditionalDate"};break;case"dateUsLong":case"date_us_long":n={pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG",type:"regex"};break;case"dateUsLongBetween":case"date_us_long_between":case"betweenDateUsLong":case"between_date_us_long":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_long:01/01/1990,12/31/2015";n={condition:[">=","<="],dateType:"US_LONG",params:[_[0],_[1]],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG_BETWEEN",type:"conditionalDate"};break;case"dateUsLongMax":case"date_us_long_max":case"maxDateUsLong":case"max_date_us_long":n={condition:"<=",dateType:"US_LONG",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG_MAX",type:"conditionalDate"};break;case"dateUsLongMin":case"date_us_long_min":case"minDateUsLong":case"min_date_us_long":n={condition:">=",dateType:"US_LONG",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG_MIN",type:"conditionalDate"};break;case"dateUsShort":case"date_us_short":n={pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT",type:"regex"};break;case"dateUsShortBetween":case"date_us_short_between":case"betweenDateUsShort":case"between_date_us_short":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_short:01/01/90,12/31/15";n={condition:[">=","<="],dateType:"US_SHORT",params:[_[0],_[1]],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateUsShortMax":case"date_us_short_max":case"maxDateUsShort":case"max_date_us_short":n={condition:"<=",dateType:"US_SHORT",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT_MAX",type:"conditionalDate"};break;case"dateUsShortMin":case"date_us_short_min":case"minDateUsShort":case"min_date_us_short":n={condition:">=",dateType:"US_SHORT",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT_MIN",type:"conditionalDate"};break;case"email":n={pattern:"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$",message:"INVALID_EMAIL",type:"regex"};break;case"exactLen":case"exact_len":n={pattern:"^.{"+r+"}$",message:"INVALID_EXACT_LEN",params:[r],type:"regex"};break;case"float":n={pattern:"^\\d*\\.{1}\\d+$",message:"INVALID_FLOAT",type:"regex"};break;case"floatSigned":case"float_signed":n={pattern:"^[-+]?\\d*\\.{1}\\d+$",message:"INVALID_FLOAT_SIGNED",type:"regex"};break;case"iban":n={pattern:"^[a-zA-Z]{2}\\d{2}\\s?([0-9a-zA-Z]{4}\\s?){4}[0-9a-zA-Z]{2}$",message:"INVALID_IBAN",type:"regex"};break;case"int":case"integer":n={pattern:"^\\d+$",message:"INVALID_INTEGER",type:"regex"};break;case"intSigned":case"integerSigned":case"int_signed":case"integer_signed":n={pattern:"^[+-]?\\d+$",message:"INVALID_INTEGER_SIGNED",type:"regex"};break;case"ipv4":n={pattern:"^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$",message:"INVALID_IPV4",type:"regex"};break;case"ipv6":n={pattern:"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$",message:"INVALID_IPV6",type:"regex"};break;case"match":var e=r.split(",");n={message:"INVALID_INPUT_MATCH",params:e,type:"match"};break;case"maxLen":case"max_len":n={pattern:"^.{0,"+r+"}$",message:"INVALID_MAX_CHAR",params:[r],type:"regex"};break;case"maxNum":case"max_num":n={condition:"<=",message:"INVALID_MAX_NUM",params:[r],type:"conditionalNumber"};break;case"minLen":case"min_len":n={pattern:"^.{"+r+",}$",message:"INVALID_MIN_CHAR",params:[r],type:"regex"};break;case"minNum":case"min_num":n={condition:">=",message:"INVALID_MIN_NUM",params:[r],type:"conditionalNumber"};break;case"numeric":n={pattern:"^\\d*\\.?\\d+$",message:"INVALID_NUMERIC",type:"regex"};break;case"numericSigned":case"numeric_signed":n={pattern:"^[-+]?\\d*\\.?\\d+$",message:"INVALID_NUMERIC_SIGNED",type:"regex"};break;case"regex":n={pattern:t.pattern,message:"INVALID_PATTERN",params:[t.message],type:"regex"};break;case"required":n={pattern:"\\S+",message:"INVALID_REQUIRED",type:"regex"};break;case"url":n={pattern:"(http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?",message:"INVALID_URL",type:"regex"};break;case"time":n={pattern:"^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$",message:"INVALID_TIME",type:"regex"}}return n.altText=a,n}var a={getElementValidators:e};return a}]); +angular.module("ghiscoding.validation").factory("validationCommon",["$rootScope","$timeout","$translate","validationRules",function(t,e,a,r){function i(){var t=this,e={};t.validators=[],t.typingLimit=V,t.validatorAttrs.hasOwnProperty("debounce")?t.typingLimit=parseInt(t.validatorAttrs.debounce,10):t.validatorAttrs.hasOwnProperty("typingLimit")?t.typingLimit=parseInt(t.validatorAttrs.typingLimit,10):t.scope.$validationOptions&&t.scope.$validationOptions.hasOwnProperty("debounce")&&(t.typingLimit=parseInt(t.scope.$validationOptions.debounce,10));var a=t.validatorAttrs.hasOwnProperty("rules")?t.validatorAttrs.rules:t.validatorAttrs.validation;if(a.indexOf("regex:")>=0){var i=a.match("regex:(.*?):regex");if(i.length<2)throw'Regex validator within the validation needs to be define with an opening "regex:" and a closing ":regex", please review your validator.';var n=i[1].split(":=");e={message:n[0],pattern:n[1]},a=a.replace(i[0],"regex:")}var s=a.split("|");if(s){t.bFieldRequired=a.indexOf("required")>=0?!0:!1;for(var l=0,o=s.length;o>l;l++){var d=s[l].split(":"),u=s[l].indexOf("alt=")>=0?!0:!1;t.validators[l]=r.getElementValidators({altText:u===!0?2===d.length?d[1]:d[2]:"",customRegEx:e,rule:d[0],ruleParams:u&&2===d.length?null:d[1]})}}return t}function n(t){return y(F,"fieldName",t)}function s(){return F}function l(t,e,a,r){this.scope=t,this.elm=e,this.ctrl=r,this.validatorAttrs=a,f(e,a,r,t),this.defineValidation()}function o(){var t=this;return t.bFieldRequired}function d(t){var e=A(F,"fieldName",t);e>=0&&F.splice(e,1)}function u(t,e){var a=A(t,"field",e);a>=0&&t.splice(a,1),a=A(U,"field",e),a>=0&&U.splice(a,1)}function p(t){N=t}function m(t){T=t}function c(t,e){var r=this;e&&e.obj&&(r=e.obj,r.validatorAttrs=e.obj.attrs);var i=e&&e.elm?e.elm:r.elm,n=i&&i.attr("name")?i.attr("name"):null;if("undefined"==typeof n||null===n)throw'Angular-Validation Service requires you to have a (name="") attribute on the element to validate... Your element is: ng-model="'+i.attr("ng-model")+'"';var s=e&&e.translate?a.instant(t):t,l=n.replace(/[|&;$%@"<>()+,\[\]\{\}]/g,""),o=null;if(r.validatorAttrs&&r.validatorAttrs.hasOwnProperty("validationErrorTo")){var d=r.validatorAttrs.validationErrorTo.charAt(0),u="."===d||"#"===d?r.validatorAttrs.validationErrorTo:"#"+r.validatorAttrs.validationErrorTo;o=angular.element(document.querySelector(u))}o&&0!==o.length||(o=angular.element(document.querySelector(".validation-"+l)));var p=e&&e.isSubmitted?e.isSubmitted:!1;e&&!e.isValid&&(p||r.ctrl.$dirty||r.ctrl.$touched)?o.length>0?o.text(s):i.after(''+s+""):o.text("")}function g(t,e){var r,i,s=this,l=!0,o=!0,d="";"undefined"==typeof t&&(t="");for(var u=s.validatorAttrs&&s.validatorAttrs.name?s.validatorAttrs.name:s.attrs&&s.attrs.name?s.attrs.name:s.elm.attr("name"),p=n(u),m=s.validatorAttrs.hasOwnProperty("rules")?s.validatorAttrs.rules:s.validatorAttrs.validation,c=0,g=s.validators.length;g>c;c++){if(i=s.validators[c],"conditionalDate"===i.type){if(r=new RegExp(i.pattern,"i"),l=("\\S+"===i.pattern||m&&"required"===i.pattern)&&null===t?!1:r.test(t)){var f=i.dateType,y=S(t,f).getTime();if(2==i.params.length){var b=S(i.params[0],f).getTime(),A=S(i.params[1],f).getTime(),O=R(i.condition[0],y,b),E=R(i.condition[1],y,A);l=O&&E?!0:!1}else{var x=S(i.params[0],f).getTime();l=R(i.condition,y,x)}}}else if("conditionalNumber"===i.type)if(2==i.params.length){var O=R(i.condition[0],parseFloat(t),parseFloat(i.params[0])),E=R(i.condition[1],parseFloat(t),parseFloat(i.params[1]));l=O&&E?!0:!1}else l=R(i.condition,parseFloat(t),parseFloat(i.params[0]));else if("match"===i.type){var $=i.params[0],w=s.scope.$eval($);l=w===t&&!!t}else if("remote"===i.type&&""!==t){s.ctrl.$processing=!0;var N=i.params[0],V=s.scope[N],F="function"==typeof V?V():null;if(!F||"function"!=typeof F.then)throw"Remote Validation requires a declared function (in your Controller) which also returns a promise, please review your code.";s.ctrl.$setValidity("remote",!1),function(t){F.then(function(a){s.ctrl.$processing=!1;var r=d+" ";"boolean"==typeof a?l=a?!0:!1:"object"==typeof a&&(l=a.isValid?!0:!1),l===!1&&(p.isValid=!1,r+=a.message?a.message:t,v(s,p,r,!1,e)),l===!0&&o===!0&&(p.isValid=!0,s.ctrl.$setValidity("remote",!0),v(s,p,"",!0,e))})}(i.altText)}else s.elm.prop("disabled")||1==parseInt(s.elm.attr("ng-disabled"))||"true"===s.elm.attr("ng-disabled")?l=!0:"string"==typeof t&&""===t&&"NUMBER"===s.elm.prop("type").toUpperCase()?l=!1:(r=new RegExp(i.pattern,"i"),l=("\\S+"===i.pattern||m&&"required"===i.pattern)&&null===t?!1:r.test(t));(!s.bFieldRequired&&!t||s.elm.prop("disabled")||1==parseInt(s.elm.attr("ng-disabled"))||"true"===s.elm.attr("ng-disabled"))&&(l=!0),l||(o=!1,function(t,r,i){var n=i.message;i.altText&&i.altText.length>0&&(n=i.altText.replace("alt=","")),a(n).then(function(a){d.length>0&&T?d=" "+(i&&i.params?String.format(a,i.params):a):d+=" "+(i&&i.params?String.format(a,i.params):a),v(s,t,d,o,e)})["catch"](function(){i.altText&&i.altText.length>0&&(d.length>0&&T?d=" "+n:d+=" "+n,v(s,t,d,o,e))})}(p,l,i))}return l&&(h(s,""),s.updateErrorMsg("",{isValid:l})),p&&(p.isValid=o,o&&(p.message="")),o}function f(t,e,r,i){var n=e.name?e.name:t.attr("name"),s=e&&e.friendlyName?a.instant(e.friendlyName):"",l={fieldName:n,friendlyName:s,elm:t,attrs:e,ctrl:r,scope:i,isValid:!1,message:""},o=A(F,"fieldName",t.attr("name"));return o>=0?F[o]=l:F.push(l),F}function v(t,e,a,r,i){a=a.trim(),h(e,a),e&&(e.message=a),i&&!e.isValid?t.updateErrorMsg(a,{isValid:r}):e&&e.isValid&&h(e,"")}function h(t,e){var r=t.validatorAttrs&&t.validatorAttrs.name?t.validatorAttrs.name:t.attrs&&t.attrs.name?t.attrs.name:t.elm.attr("name"),i=O(r,t),n=A(U,"field",r);if(n>=0&&""===e)U.splice(n,1);else if(""!==e){var s=t.attrs&&t.friendlyName?a.instant(t.friendlyName):"",l={field:r,friendlyName:s,message:e,formName:i?i.$name:null};n>=0?U[n]=l:U.push(l)}return t.scope.$validationSummary=U,i&&(i.$validationSummary=b(U,"formName",i.$name)),U}function y(t,e,a){for(var r=0;r8?t.substring(9).split(":"):null;break;case"UK":case"EURO":case"EURO_SHORT":case"EURO-SHORT":case"EUROPE":a=t.substring(0,8),r=t.substring(2,3),i=E(a,r),o=i[0],l=i[1],s=parseInt(i[2])<50?"20"+i[2]:"19"+i[2],n=t.length>8?t.substring(9).split(":"):null;break;case"US_LONG":case"US-LONG":a=t.substring(0,10),r=t.substring(2,3),i=E(a,r),l=i[0],o=i[1],s=i[2],n=t.length>8?t.substring(9).split(":"):null;break;case"US":case"US_SHORT":case"US-SHORT":a=t.substring(0,8),r=t.substring(2,3),i=E(a,r),l=i[0],o=i[1],s=parseInt(i[2])<50?"20"+i[2]:"19"+i[2],n=t.length>8?t.substring(9).split(":"):null;break;case"ISO":default:a=t.substring(0,10),r=t.substring(4,5),i=E(a,r),s=i[0],l=i[1],o=i[2],n=t.length>10?t.substring(11).split(":"):null}var d=n&&3===n.length?n[0]:0,u=n&&3===n.length?n[1]:0,p=n&&3===n.length?n[2]:0;return new Date(s,l-1,o,d,u,p)}function E(t,e){var a=[];switch(e){case"/":a=t.split("/");break;case".":a=t.split(".");break;case"-":default:a=t.split("-")}return a}function R(t,e,a){var r=!1;switch(t){case"<":r=a>e?!0:!1;break;case"<=":r=a>=e?!0:!1;break;case">":r=e>a?!0:!1;break;case">=":r=e>=a?!0:!1;break;case"!=":case"<>":r=e!=a?!0:!1;break;case"=":case"==":r=e==a?!0:!1;break;default:r=!1}return r}function x(){return this.replace(/^\s+|\s+$/g,"")}function $(){var t=Array.isArray(arguments[0])?arguments[0]:arguments;return this.replace(/{(\d+)}/g,function(e,a){return"undefined"!=typeof t[a]?t[a]:e})}function w(t){var e=Array.isArray(arguments[1])?arguments[1]:Array.prototype.slice.call(arguments,1);return t.replace(/{(\d+)}/g,function(t,a){return"undefined"!=typeof e[a]?e[a]:t})}var N=!1,T=!1,V=1e3,F=[],U=[];t.$on("$routeChangeStart",function(){N||(T=!1,F=[],U=[])});var L=function(t,e,a,r){this.timer=null,this.bFieldRequired=!1,this.validators=[],this.typingLimit=V,this.scope=t,this.elm=e,this.ctrl=r,this.validatorAttrs=a,t&&e&&a&&r&&(f(e,a,r,t),this.defineValidation())};return L.prototype.defineValidation=i,L.prototype.getFormElementByName=n,L.prototype.getFormElements=s,L.prototype.isFieldRequired=o,L.prototype.initialize=l,L.prototype.removeFromValidationSummary=u,L.prototype.removeFromFormElementObjectList=d,L.prototype.setBypassRootScopeReset=p,L.prototype.setDisplayOnlyLastErrorMsg=m,L.prototype.updateErrorMsg=c,L.prototype.validate=g,String.prototype.trim=x,String.prototype.format=$,String.format=w,L}]); +angular.module("ghiscoding.validation").factory("validationRules",[function(){function e(e){var a="undefined"!=typeof e.altText?e.altText.replace("alt=",""):null,t=e.hasOwnProperty("customRegEx")?e.customRegEx:null,s=e.hasOwnProperty("rule")?e.rule:null,r=e.hasOwnProperty("ruleParams")?e.ruleParams:null,n={};switch(s){case"alpha":n={pattern:"^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ])+$",message:"INVALID_ALPHA",type:"regex"};break;case"alphaSpaces":case"alpha_spaces":n={pattern:"^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ\\s])+$",message:"INVALID_ALPHA_SPACE",type:"regex"};break;case"alphaNum":case"alpha_num":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ])+$",message:"INVALID_ALPHA_NUM",type:"regex"};break;case"alphaNumSpaces":case"alpha_num_spaces":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ\\s])+$",message:"INVALID_ALPHA_NUM_SPACE",type:"regex"};break;case"alphaDash":case"alpha_dash":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ_-])+$",message:"INVALID_ALPHA_DASH",type:"regex"};break;case"alphaDashSpaces":case"alpha_dash_spaces":n={pattern:"^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ\\s_-])+$",message:"INVALID_ALPHA_DASH_SPACE",type:"regex"};break;case"betweenLen":case"between_len":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_len:1,5";n={pattern:"^.{"+_[0]+","+_[1]+"}$",message:"INVALID_BETWEEN_CHAR",params:[_[0],_[1]],type:"regex"};break;case"betweenNum":case"between_num":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_num:1,5";n={condition:[">=","<="],message:"INVALID_BETWEEN_NUM",params:[_[0],_[1]],type:"conditionalNumber"};break;case"boolean":n={pattern:"^(true|True|false|False|0|1)$",message:"INVALID_BOOLEAN",type:"regex"};break;case"checked":n={pattern:"^true$",message:"INVALID_CHECKBOX_SELECTED",type:"regex"};break;case"creditCard":case"credit_card":n={pattern:"^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\\d{3})\\d{11})$",message:"INVALID_CREDIT_CARD",type:"regex"};break;case"dateEuroLong":case"date_euro_long":n={pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG",type:"regex"};break;case"dateEuroLongBetween":case"date_euro_long_between":case"betweenDateEuroLong":case"between_date_euro_long":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_long:01-01-1990,31-12-2015";n={condition:[">=","<="],dateType:"EURO_LONG",params:[_[0],_[1]],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG_BETWEEN",type:"conditionalDate"};break;case"dateEuroLongMax":case"date_euro_long_max":case"maxDateEuroLong":case"max_date_euro_long":n={condition:"<=",dateType:"EURO_LONG",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG_MAX",type:"conditionalDate"};break;case"dateEuroLongMin":case"date_euro_long_min":case"minDateEuroLong":case"min_date_euro_long":n={condition:">=",dateType:"EURO_LONG",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/](19|20)\\d\\d$",message:"INVALID_DATE_EURO_LONG_MIN",type:"conditionalDate"};break;case"dateEuroShort":case"date_euro_short":n={pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT",type:"regex"};break;case"dateEuroShortBetween":case"date_euro_short_between":case"betweenDateEuroShort":case"between_date_euro_short":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_euro_short:01-01-90,31-12-15";n={condition:[">=","<="],dateType:"EURO_SHORT",params:[_[0],_[1]],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateEuroShortMax":case"date_euro_short_max":case"maxDateEuroShort":case"max_date_euro_short":n={condition:"<=",dateType:"EURO_SHORT",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT_MAX",type:"conditionalDate"};break;case"dateEuroShortMin":case"date_euro_short_min":case"minDateEuroShort":case"min_date_euro_short":n={condition:">=",dateType:"EURO_SHORT",params:[r],pattern:"^(0[1-9]|[12][0-9]|3[01])[-/](0[1-9]|1[012])[-/]\\d\\d$",message:"INVALID_DATE_EURO_SHORT_MIN",type:"conditionalDate"};break;case"dateIso":case"date_iso":n={pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO",type:"regex"};break;case"dateIsoBetween":case"date_iso_between":case"betweenDateIso":case"between_date_iso":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_iso:1990-01-01,2000-12-31";n={condition:[">=","<="],dateType:"ISO",params:[_[0],_[1]],pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO_BETWEEN",type:"conditionalDate"};break;case"dateIsoMax":case"date_iso_max":case"maxDateIso":case"max_date_iso":n={condition:"<=",dateType:"ISO",params:[r],pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO_MAX",type:"conditionalDate"};break;case"dateIsoMin":case"date_iso_min":case"minDateIso":case"min_date_iso":n={condition:">=",dateType:"ISO",params:[r],pattern:"^(19|20)\\d\\d([-])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])$",message:"INVALID_DATE_ISO_MIN",type:"conditionalDate"};break;case"dateUsLong":case"date_us_long":n={pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG",type:"regex"};break;case"dateUsLongBetween":case"date_us_long_between":case"betweenDateUsLong":case"between_date_us_long":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_long:01/01/1990,12/31/2015";n={condition:[">=","<="],dateType:"US_LONG",params:[_[0],_[1]],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG_BETWEEN",type:"conditionalDate"};break;case"dateUsLongMax":case"date_us_long_max":case"maxDateUsLong":case"max_date_us_long":n={condition:"<=",dateType:"US_LONG",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG_MAX",type:"conditionalDate"};break;case"dateUsLongMin":case"date_us_long_min":case"minDateUsLong":case"min_date_us_long":n={condition:">=",dateType:"US_LONG",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/](19|20)\\d\\d$",message:"INVALID_DATE_US_LONG_MIN",type:"conditionalDate"};break;case"dateUsShort":case"date_us_short":n={pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT",type:"regex"};break;case"dateUsShortBetween":case"date_us_short_between":case"betweenDateUsShort":case"between_date_us_short":var _=r.split(",");if(2!==_.length)throw"This validation must include exactly 2 params separated by a comma (,) ex.: between_date_us_short:01/01/90,12/31/15";n={condition:[">=","<="],dateType:"US_SHORT",params:[_[0],_[1]],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT_BETWEEN",type:"conditionalDate"};break;case"dateUsShortMax":case"date_us_short_max":case"maxDateUsShort":case"max_date_us_short":n={condition:"<=",dateType:"US_SHORT",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT_MAX",type:"conditionalDate"};break;case"dateUsShortMin":case"date_us_short_min":case"minDateUsShort":case"min_date_us_short":n={condition:">=",dateType:"US_SHORT",params:[r],pattern:"^(0[1-9]|1[012])[-/](0[1-9]|[12][0-9]|3[01])[-/]\\d\\d$",message:"INVALID_DATE_US_SHORT_MIN",type:"conditionalDate"};break;case"email":n={pattern:"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$",message:"INVALID_EMAIL",type:"regex"};break;case"exactLen":case"exact_len":n={pattern:"^.{"+r+"}$",message:"INVALID_EXACT_LEN",params:[r],type:"regex"};break;case"float":n={pattern:"^\\d*\\.{1}\\d+$",message:"INVALID_FLOAT",type:"regex"};break;case"floatSigned":case"float_signed":n={pattern:"^[-+]?\\d*\\.{1}\\d+$",message:"INVALID_FLOAT_SIGNED",type:"regex"};break;case"iban":n={pattern:"^[a-zA-Z]{2}\\d{2}\\s?([0-9a-zA-Z]{4}\\s?){4}[0-9a-zA-Z]{2}$",message:"INVALID_IBAN",type:"regex"};break;case"int":case"integer":n={pattern:"^\\d+$",message:"INVALID_INTEGER",type:"regex"};break;case"intSigned":case"integerSigned":case"int_signed":case"integer_signed":n={pattern:"^[+-]?\\d+$",message:"INVALID_INTEGER_SIGNED",type:"regex"};break;case"ipv4":n={pattern:"^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$",message:"INVALID_IPV4",type:"regex"};break;case"ipv6":n={pattern:"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$",message:"INVALID_IPV6",type:"regex"};break;case"match":var e=r.split(",");n={message:"INVALID_INPUT_MATCH",params:e,type:"match"};break;case"maxLen":case"max_len":n={pattern:"^.{0,"+r+"}$",message:"INVALID_MAX_CHAR",params:[r],type:"regex"};break;case"maxNum":case"max_num":n={condition:"<=",message:"INVALID_MAX_NUM",params:[r],type:"conditionalNumber"};break;case"minLen":case"min_len":n={pattern:"^.{"+r+",}$",message:"INVALID_MIN_CHAR",params:[r],type:"regex"};break;case"minNum":case"min_num":n={condition:">=",message:"INVALID_MIN_NUM",params:[r],type:"conditionalNumber"};break;case"numeric":n={pattern:"^\\d*\\.?\\d+$",message:"INVALID_NUMERIC",type:"regex"};break;case"numericSigned":case"numeric_signed":n={pattern:"^[-+]?\\d*\\.?\\d+$",message:"INVALID_NUMERIC_SIGNED",type:"regex"};break;case"regex":n={pattern:t.pattern,message:"INVALID_PATTERN",params:[t.message],type:"regex"};break;case"remote":n={message:"",params:[r],type:"remote"};break;case"required":n={pattern:"\\S+",message:"INVALID_REQUIRED",type:"regex"};break;case"url":n={pattern:"(http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?",message:"INVALID_URL",type:"regex"};break;case"time":n={pattern:"^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$",message:"INVALID_TIME",type:"regex"}}return n.altText=a,n}var a={getElementValidators:e};return a}]); angular.module("ghiscoding.validation").service("validationService",["$timeout","validationCommon",function(e,o){function t(o,t,i){var n=this,a={};if("string"==typeof o&&"string"==typeof t?(a.elmName=o,a.rules=t,a.friendlyName="string"==typeof i?i:""):a=o,"object"!=typeof a||!a.hasOwnProperty("elmName")||!a.hasOwnProperty("rules")||!a.hasOwnProperty("scope")&&"undefined"==typeof n.validationAttrs.scope)throw"Angular-Validation-Service requires at least the following 3 attributes: {elmName, rules, scope}";return a.elm=angular.element(document.querySelector('[name="'+a.elmName+'"]:not([disabled]):not([ng-disabled]')),"object"!=typeof a.elm||0===a.elm.length?n:(new RegExp("{{(.*?)}}").test(a.elmName)&&(a.elmName=$interpolate(a.elmName)(a.scope)),a.name=a.elmName,a.elm.bind("blur",p=function(e){f||(n.commonObj.initialize(a.scope,a.elm,a,a.ctrl),n.commonObj.typingLimit=0,c(n,e.target.value))}),a=s(n.validationAttrs,a),a.scope.$watch(a.elmName,function(o,t){return void 0===o&&void 0!==t?(e.cancel(n.timer),void n.commonObj.ctrl.$setValidity("validation",n.commonObj.validate("",!0))):(a.ctrl=angular.element(a.elm).controller("ngModel"),a.value=o,n.commonObj.initialize(a.scope,a.elm,a,a.ctrl),void c(n,o))},!0),n)}function i(e){var o=this,t="",i=!0;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"checkFormValidity() requires a valid Angular Form or $scope object passed as argument to function properly (ex.: $scope.form1 OR $scope).";for(var n=0,a=e.$validationSummary.length;a>n;n++)if(i=!1,t=e.$validationSummary[n].field){var r=o.commonObj.getFormElementByName(t);r.elm&&r.elm.length>0&&("function"==typeof r.ctrl.$setTouched&&r.ctrl.$setTouched(),o.commonObj.updateErrorMsg(e.$validationSummary[n].message,{isSubmitted:!0,isValid:r.isValid,obj:r}))}return i}function n(e){var o=this;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"clearInvalidValidatorsInSummary() requires a valid Angular Form or $scope object passed as argument to function properly (ex.: $scope.form1 OR $scope).";for(var t=[],i=0,n=e.$validationSummary.length;n>i;i++)t.push(e.$validationSummary[i].field);for(i=0,n=t.length;n>i;i++)t[i]&&(o.commonObj.removeFromFormElementObjectList(t[i]),o.commonObj.removeFromValidationSummary(e.$validationSummary,t[i]))}function a(e,o){var t,i=this;if("undefined"==typeof e||"undefined"==typeof e.$validationSummary)throw"removeValidator() only works with Validation that were defined by the Service (not by the Directive) and requires a valid Angular Form or $scope object passed as argument to function properly (ex.: $scope.form1 OR $scope).";if("undefined"==typeof i.commonObj.scope&&"undefined"!=typeof i.validationAttrs.scope&&(i.commonObj.scope=i.validationAttrs.scope),o instanceof Array)for(var n=0,a=o.length;a>n;n++)t=i.commonObj.getFormElementByName(o[n]),t.elm.removeAttr("validation"),u(i,t,e.$validationSummary);else t=i.commonObj.getFormElementByName(o),t.elm.removeAttr("validation"),u(i,t,e.$validationSummary);return i}function r(e){var o=this,t="boolean"==typeof e?e:!0;o.commonObj.setBypassRootScopeReset(t)}function m(e){var o=this,t="boolean"==typeof e?e:!0;o.commonObj.setDisplayOnlyLastErrorMsg(t)}function l(e){var o=this;return o.validationAttrs=e,o}function c(o,t){return o.commonObj.validate(t,!1),o.commonObj.isFieldRequired()||""!==t&&null!==t&&"undefined"!=typeof t?(f=!1,(o.commonObj.isFieldRequired()||t)&&o.commonObj.ctrl.$setValidity("validation",!1),""!==t&&"undefined"!=typeof t||"NUMBER"!==o.commonObj.elm.prop("type").toUpperCase()?"SELECT"===o.commonObj.elm.prop("tagName").toUpperCase()?(o.commonObj.ctrl.$setValidity("validation",o.commonObj.validate(t,!0)),t):("undefined"!=typeof t&&(o.commonObj.updateErrorMsg(""),e.cancel(o.timer),o.timer=e(function(){o.commonObj.scope.$evalAsync(o.commonObj.ctrl.$setValidity("validation",o.commonObj.validate(t,!0)))},o.commonObj.typingLimit)),t):(e.cancel(o.timer),o.commonObj.ctrl.$setValidity("validation",o.commonObj.validate(t,!0)),t)):(d(o),t)}function d(o){f=!0,e.cancel(self.timer),o.commonObj.updateErrorMsg(""),o.commonObj.ctrl.$setValidity("validation",!0),"undefined"!=typeof p&&o.commonObj.elm.unbind("blur",p)}function s(e,o){var t={};for(var i in e)t[i]=e[i];for(var i in o)t[i]=o[i];return t}function u(e,o,t){if("undefined"!=typeof e.commonObj.scope){var i=e.commonObj.scope.$watch(o.fieldName,function(){});i(),"function"==typeof o.ctrl.$setUntouched&&o.ctrl.$setUntouched(),o.ctrl.$setPristine(),o.ctrl.$setValidity("validation",!0),e.commonObj.removeFromValidationSummary(t,o.fieldName),e.commonObj.updateErrorMsg("",{isValid:!0,obj:o})}}var p,f=!1,y=function(){this.validationAttrs={},this.commonObj=new o};return y.prototype.addValidator=t,y.prototype.checkFormValidity=i,y.prototype.removeValidator=a,y.prototype.setBypassRootScopeReset=r,y.prototype.setDisplayOnlyLastErrorMsg=m,y.prototype.setGlobalOptions=l,y.prototype.clearInvalidValidatorsInSummary=n,y}]); \ No newline at end of file diff --git a/index.html b/index.html index 13027e6..3f9c146 100644 --- a/index.html +++ b/index.html @@ -26,8 +26,8 @@

Angular-Validation Directive|Service (ghiscoding)

Type:
- - + +
diff --git a/locales/validation/en.json b/locales/validation/en.json index 9e8d52a..793db0f 100644 --- a/locales/validation/en.json +++ b/locales/validation/en.json @@ -56,6 +56,7 @@ "AREA1": "TextArea: Alphanumeric + Minimum(15) + Required", "ERRORS": "Errors", "CHANGE_LANGUAGE": "Change language", + "INPUT1": "Remote validation - Type \"abc\" for a valid answer ", "INPUT2": "Number positive or negative -- input type=\"number\" -- Error on non-numeric characters ", "INPUT3": "Floating number range (integer excluded) -- between_num:x,y OR min_num:x|max_num:y ", "INPUT4": "Multiple Validations + Custom Regex of Date Code (YYWW)", diff --git a/locales/validation/es.json b/locales/validation/es.json index b49912d..9675363 100644 --- a/locales/validation/es.json +++ b/locales/validation/es.json @@ -56,6 +56,7 @@ "AREA1": "Area de texto: Alfanúmerica + Minimo(15) + Requerido", "ERRORS": "Errores", "CHANGE_LANGUAGE": "Cambiar idioma", + "INPUT1": "Validación Remota - Escriba \"abc\" para una respuesta válida ", "INPUT2": "Número positivo o negativo -- input type=\"number\" -- Error o caracteres no númericos ", "INPUT3": "Rango decimal (Los números enteros no son validos) -- between_num:x,y ó min_num:x|max_num:y ", "INPUT4": "Multiples validaciones + Código de fecha personalizado (YYWW)", diff --git a/locales/validation/fr.json b/locales/validation/fr.json index 3509eb3..6bca498 100644 --- a/locales/validation/fr.json +++ b/locales/validation/fr.json @@ -56,6 +56,7 @@ "AREA1": "TextArea: Alphanumérique + Minimum(15) + Required", "ERRORS": "Erreurs", "CHANGE_LANGUAGE": "Changer de langue", + "INPUT1": "Validation à Distance - Taper \"abc\" pour une réponse valide ", "INPUT2": "Nombre positif ou négatif -- input type=\"number\" -- Erreur sur caractères non-numérique", "INPUT3": "Intervalle de Nombre Flottant (entier exclu) -- between_num:x,y OU min_num:x|max_num:y", "INPUT4": "Multiple Validations + Regex Personnalisé d'un Code Date (AASS)", diff --git a/locales/validation/no.json b/locales/validation/no.json index 2cc53d6..8f437ee 100644 --- a/locales/validation/no.json +++ b/locales/validation/no.json @@ -56,6 +56,7 @@ "AREA1": "TextArea: Alfanumerisk + Minimum(15) + Påkrevd", "ERRORS": "Feil", "CHANGE_LANGUAGE": "Endre språk.", + "INPUT1": "Ekstern Validering - Type \"abc\" for et gyldig svar ", "INPUT2": "Positivt eller negativt nummer -- input type=\"number\" -- Feil på ikke-numeriske tegn ", "INPUT3": "Flyttalssutvalg (heltall ekskludert) -- between_num:x,y eller min_num:x|max_num:y ", "INPUT4": "Multiple Valideringer + Tilpasset Regex av dato kode (YYWW)", diff --git a/locales/validation/ru.json b/locales/validation/ru.json index 71052b0..284ed83 100644 --- a/locales/validation/ru.json +++ b/locales/validation/ru.json @@ -56,6 +56,7 @@ "AREA1": "TextArea: Буквенно-цифровой + Минимум(15) + Обязательно + Обязательно для заполнения", "ERRORS": "Ошибки", "CHANGE_LANGUAGE": "Изменить язык", + "INPUT1": "дистанционное проверки - введите \"abc\" для действительного ответа ", "INPUT2": "Число положительное или отрицательное -- input type=\"number\" -- Ошибка на не числовых значениях ", "INPUT3": "Диапазон дробного числа (включая целые) -- between_num:x,y или min_num:x|max_num:y ", "INPUT4": "Множественная проверка + Пользовательское регулярное выражение формата даты (YYWW)", diff --git a/package.json b/package.json index 26793bd..da4ca37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-validation-ghiscoding", - "version": "1.3.24", + "version": "1.3.25", "author": "Ghislain B.", "description": "Angular-Validation Directive and Service (ghiscoding)", "main": "app.js", diff --git a/protractor/full_tests_spec.js b/protractor/full_tests_spec.js index e42939f..4a53215 100644 --- a/protractor/full_tests_spec.js +++ b/protractor/full_tests_spec.js @@ -105,9 +105,9 @@ } }, 420000); - }); // describe: When clicking on top menu ... - })(types, k); - } // for() + }); // describe: When clicking on top menu ... + })(types, k); // closure + } // for() }); diff --git a/protractor/mixed_validation_spec.js b/protractor/mixed_validation_spec.js index 79a00f5..6f29b49 100644 --- a/protractor/mixed_validation_spec.js +++ b/protractor/mixed_validation_spec.js @@ -3,48 +3,48 @@ var formElementNames = ['input2', 'input3', 'input4', 'input5', 'input6', 'input7', 'input8', 'input9', 'input10', 'input11', 'input12', 'select1', 'input13', 'input14', 'input15', 'input16', 'input17', 'input18', 'input19', 'area1']; var formElementSummaryNames = ['input2', 'input3', 'input4', 'Email', 'input6', 'input7', 'Credit Card', 'input9', 'input10', 'input11', 'select1', 'input13', 'input15', 'input16', 'input17', 'input18', 'input19', 'area1']; var formElementTexts = [ - 'Number positive or negative -- input type="number" -- Error on non-numeric characters', - 'Floating number range (integer excluded) -- between_num:x,y OR min_num:x|max_num:y', - 'Multiple Validations + Custom Regex of Date Code (YYWW)', - 'Email', - 'URL', - 'IP (IPV4)', - 'Credit Card', - 'Between(2,6) Characters', - 'Date ISO (yyyy-mm-dd)', - 'Date US LONG (mm/dd/yyyy)', - 'Time (hh:mm OR hh:mm:ss) -- NOT Required', - 'Required (select) -- validation with (blur) EVENT', - 'AlphaDashSpaces + Required + Minimum(5) Characters -- MUST USE: validation-error-to=" "', - 'Alphanumeric + Required -- NG-DISABLED', - 'Password', - 'Password Confirmation', - 'Alphanumeric + Exactly(3) + Required -- debounce(3sec)', - 'Date ISO (yyyy-mm-dd) -- minimum condition >= 2001-01-01', - 'Date US SHORT (mm/dd/yy) -- between the dates 12/01/99 and 12/31/15', - 'TextArea: Alphanumeric + Minimum(15) + Required' + 'Number positive or negative -- input type="number" -- Error on non-numeric characters', + 'Floating number range (integer excluded) -- between_num:x,y OR min_num:x|max_num:y', + 'Multiple Validations + Custom Regex of Date Code (YYWW)', + 'Email', + 'URL', + 'IP (IPV4)', + 'Credit Card', + 'Between(2,6) Characters', + 'Date ISO (yyyy-mm-dd)', + 'Date US LONG (mm/dd/yyyy)', + 'Time (hh:mm OR hh:mm:ss) -- NOT Required', + 'Required (select) -- validation with (blur) EVENT', + 'AlphaDashSpaces + Required + Minimum(5) Characters -- MUST USE: validation-error-to=" "', + 'Alphanumeric + Required -- NG-DISABLED', + 'Password', + 'Password Confirmation', + 'Alphanumeric + Exactly(3) + Required -- debounce(3sec)', + 'Date ISO (yyyy-mm-dd) -- minimum condition >= 2001-01-01', + 'Date US SHORT (mm/dd/yy) -- between the dates 12/01/99 and 12/31/15', + 'TextArea: Alphanumeric + Minimum(15) + Required' ]; var errorMessages = [ - 'Must be a positive or negative number. Field is required.', - 'May only contain a positive or negative float value (integer excluded). Needs to be a numeric value, between -0.6 and 99.5. Field is required.', - 'Must have a length of exactly 4 characters. Must be following this format: YYWW. Field is required. Must be a positive integer.', - 'Must be a valid email address. Field is required. Must be at least 6 characters.', - 'Must be a valid URL. Field is required.', - 'Must be a valid IP (IPV4). Field is required.', - 'Must be a valid credit card number. Field is required.', - 'Text must be between 2 and 6 characters in length. Field is required.', - 'Must be a valid date format (yyyy-mm-dd). Field is required.', - 'Must be a valid date format (mm/dd/yyyy) OR (mm-dd-yyyy). Field is required.', - 'Must be a valid time format (hh:mm) OR (hh:mm:ss).', - 'May only contain letters. Change language', - 'Must be at least 5 characters. May only contain letters, numbers, dashes and spaces. Field is required.', - '', - 'May only contain letters. Must be at least 3 characters. Field is required.', - 'Confirmation field does not match specified field "input15". Field is required.', - 'May only contain letters and spaces. Must have a length of exactly 3 characters. Field is required.', - 'Needs to be a valid date format (yyyy-mm-dd), equal to, or higher than 2001-01-01. Field is required.', - 'Needs to be a valid date format (mm/dd/yy) OR (mm-dd-yy) between 11/28/99 and 12/31/15. Field is required.', - 'May only contain letters, numbers, dashes and spaces. Must be at least 15 characters. Field is required.' + 'Must be a positive or negative number. Field is required.', + 'May only contain a positive or negative float value (integer excluded). Needs to be a numeric value, between -0.6 and 99.5. Field is required.', + 'Must have a length of exactly 4 characters. Must be following this format: YYWW. Field is required. Must be a positive integer.', + 'Must be a valid email address. Field is required. Must be at least 6 characters.', + 'Must be a valid URL. Field is required.', + 'Must be a valid IP (IPV4). Field is required.', + 'Must be a valid credit card number. Field is required.', + 'Text must be between 2 and 6 characters in length. Field is required.', + 'Must be a valid date format (yyyy-mm-dd). Field is required.', + 'Must be a valid date format (mm/dd/yyyy) OR (mm-dd-yyyy). Field is required.', + 'Must be a valid time format (hh:mm) OR (hh:mm:ss).', + 'May only contain letters. Change language', + 'Must be at least 5 characters. May only contain letters, numbers, dashes and spaces. Field is required.', + '', + 'May only contain letters. Must be at least 3 characters. Field is required.', + 'Confirmation field does not match specified field "input15". Field is required.', + 'May only contain letters and spaces. Must have a length of exactly 3 characters. Field is required.', + 'Needs to be a valid date format (yyyy-mm-dd), equal to, or higher than 2001-01-01. Field is required.', + 'Needs to be a valid date format (mm/dd/yy) OR (mm-dd-yy) between 11/28/99 and 12/31/15. Field is required.', + 'May only contain letters, numbers, dashes and spaces. Must be at least 15 characters. Field is required.' ]; var validInputTexts = [ '10', @@ -68,281 +68,177 @@ '01/01/12', 'This is a great tool' ]; + var types = ['Directive', 'Service']; - describe('When clicking on top menu Angular-Validation >> Directive', function () { - it('Should navigate to Angular-Validation home page', function () { - browser.get('http://localhost/Github/angular-validation'); - - // Find the title element - var titleElement = element(by.css('h1')); + for(var k = 0, kln = types.length; k < kln; k++) { + // because we are dealing with promises, we better use closures to pass certain variables + (function(types, k) { + describe('When clicking on top menu Angular-Validation >> ' + types[k], function () { + it('Should navigate to Angular-Validation home page', function () { + browser.get('http://localhost/Github/angular-validation'); - // Assert that the text element has the expected value. - // Protractor patches 'expect' to understand promises. - expect(titleElement.getText()).toEqual('Angular-Validation Directive|Service (ghiscoding)'); - }); + // Find the title element + var titleElement = element(by.css('h1')); - it('Should navigate to TestingFormDirective page', function () { - browser.get('http://localhost/Github/angular-validation'); + // Assert that the text element has the expected value. + // Protractor patches 'expect' to understand promises. + expect(titleElement.getText()).toEqual('Angular-Validation Directive|Service (ghiscoding)'); + }); - var anchorLink = $('[name=btn_goto_directive]'); - anchorLink.click(); - browser.waitForAngular(); + it('Should navigate to TestingForm' + types[k] + ' page', function () { + browser.get('http://localhost/Github/angular-validation'); - // Find the sub-title element - var titleElement = element(by.css('h3')); + var anchorLink = $('[name=btn_goto_' + types[k] +']'); + anchorLink.click(); + browser.waitForAngular(); - // Assert that the text element has the expected value. - // Protractor patches 'expect' to understand promises. - expect(titleElement.getText()).toEqual('Directive'); - }); + // Find the sub-title element + var titleElement = element(by.css('h3')); - it('Should have multiple form elements with all english labels', function () { - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - var elmLabel = $('label[for=' + formElementNames[i] + ']'); - expect(elmLabel.getText()).toEqual(formElementTexts[i]); - } - }); + // Assert that the text element has the expected value. + // Protractor patches 'expect' to understand promises. + expect(titleElement.getText()).toEqual(types[k]); + }); - it('Should click and blur on each form elements and error message should display on each of them', function () { - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - // some fields are not required or disabled so no error will show up, continue to next ones - if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { - continue; - } - var elmInput = $('[name=' + formElementNames[i] + ']'); - elmInput.click(); - elmInput.sendKeys(protractor.Key.TAB); + it('Should have multiple form elements with all english labels', function () { + for (var i = 0, ln = formElementNames.length; i < ln; i++) { + var elmLabel = $('label[for=' + formElementNames[i] + ']'); + expect(elmLabel.getText()).toEqual(formElementTexts[i]); + } + }); - if (formElementNames[i] === 'select1') { - element(by.cssContainingText('option', 'en')).click(); // click on good option first - element(by.cssContainingText('option', '...')).click(); // then click on option[0], the one containing '...' + it('Should click, blur on Remote input and error message should display', function () { + var elmInput = $('[name=input1]'); + elmInput.click(); elmInput.sendKeys(protractor.Key.TAB); - //browser.sleep(5000); // sleep 5 seconds - - var elmError = $('.validation-select1'); - expect(elmError.getText()).toEqual(errorMessages[i]); - continue; - } - - var elmError = $('.validation-' + formElementNames[i]); - expect(elmError.getText()).toEqual(errorMessages[i]); - } - }); + var elmError = $('.validation-input1'); - it('Should enter valid text and make error go away', function () { - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - // some fields are not required or disabled so no error will show up, continue to next ones - if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { - continue; - } - var elmInput = $('[name=' + formElementNames[i] + ']'); - elmInput.click(); - elmInput.sendKeys(validInputTexts[i]); + // Remote check will not process unless the input is field, so at first we will see the other validator errors only. + expect(elmError.getText()).toEqual('May only contain letters. Must be at least 2 characters. Field is required.'); + }); - if (formElementNames[i] === 'select1') { - element(by.cssContainingText('option', validInputTexts[i])).click(); // click on good option + it('Should enter wrong data in Remote input and error message should display', function () { + var elmInput = $('[name=input1]'); + elmInput.click(); + elmInput.sendKeys('ab'); elmInput.sendKeys(protractor.Key.TAB); - } - - var elmError = $('.validation-' + formElementNames[i]); - expect(elmError.getText()).toEqual(''); - } - }); - - it('Should reload english route, click on submit and display all error messages', function () { - // scroll back to top if we want to be able to click on the English button - browser.executeScript('window.scrollTo(0,0);').then(function () { - var elmBtnEnglish = $('button[name=btn_english]'); - elmBtnEnglish.click(); - browser.waitForAngular(); - - var elmBtnNgSubmit = $('button[name=btn_ngSubmit]'); - elmBtnNgSubmit.click(); - browser.waitForAngular(); - - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - // some fields are not required or disabled so no error will show up, continue to next ones - if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { - continue; + browser.sleep(1500); // sleep because of our data sample having a delay of 1sec internally, we use 1.5sec on this side to be sure + + var elmError = $('.validation-input1'); + expect(elmError.getText()).toEqual('Returned error from promise.'); + }); + + it('Should enter valid data in Remote input and error message should disappear', function () { + var elmInput = $('[name=input1]'); + elmInput.clear().then(function() { + elmInput.sendKeys('abc'); + elmInput.sendKeys(protractor.Key.TAB); + browser.sleep(1500); // sleep because of our data sample having a delay of 1sec internally, we use 1.5sec on this side to be sure + + var elmError = $('.validation-input1'); + expect(elmError.getText()).toEqual(''); + }); + }); + + it('Should click, blur on each form elements and error message should display on each of them', function () { + for (var i = 0, ln = formElementNames.length; i < ln; i++) { + // some fields are not required or disabled so no error will show up, continue to next ones + if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { + continue; + } + var elmInput = $('[name=' + formElementNames[i] + ']'); + elmInput.click(); + elmInput.sendKeys(protractor.Key.TAB); + + if (formElementNames[i] === 'select1') { + element(by.cssContainingText('option', 'en')).click(); // click on good option first + element(by.cssContainingText('option', '...')).click(); // then click on option[0], the one containing '...' + elmInput.sendKeys(protractor.Key.TAB); + //browser.sleep(5000); // sleep 5 seconds + + var elmError = $('.validation-select1'); + expect(elmError.getText()).toEqual(errorMessages[i]); + continue; + } + + var elmError = $('.validation-' + formElementNames[i]); + expect(elmError.getText()).toEqual(errorMessages[i]); } - var elmError = $('.validation-' + formElementNames[i]); - expect(elmError.getText()).toEqual(errorMessages[i]); - } - }); - }); - - it('Should show ValidationSummary and contain all error messages', function () { - var elmBtnEnglish = $('button[name=btn_english]'); - elmBtnEnglish.click(); - browser.waitForAngular(); - - // showValidation checkbox should false at first but true after - var elmCheckboxShowSummary = element(by.model('displayValidationSummary')); - expect(elmCheckboxShowSummary.isSelected()).toBeFalsy(); - - var btnShowSummary = $('button[name=btn_showValidation]'); - btnShowSummary.click(); - browser.waitForAngular(); - - elmCheckboxShowSummary = element(by.model('displayValidationSummary')); - expect(elmCheckboxShowSummary.isSelected()).toBeTruthy(); - - // scroll back to top - browser.executeScript('window.scrollTo(0,0);').then(function () { - var itemRows = element.all(by.binding('message')); - var inputName; - - for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) { - // since field after input13 is part of errorMessages and is empty string, we need to skip that one - if (formElementNames[i] === 'input13') { - j++; + }); + + it('Should enter valid text and make error go away', function () { + for (var i = 0, ln = formElementNames.length; i < ln; i++) { + // some fields are not required or disabled so no error will show up, continue to next ones + if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { + continue; + } + var elmInput = $('[name=' + formElementNames[i] + ']'); + elmInput.click(); + elmInput.sendKeys(validInputTexts[i]); + + if (formElementNames[i] === 'select1') { + element(by.cssContainingText('option', validInputTexts[i])).click(); // click on good option + elmInput.sendKeys(protractor.Key.TAB); + } + + var elmError = $('.validation-' + formElementNames[i]); + expect(elmError.getText()).toEqual(''); } - expect(itemRows.get(i).getText()).toEqual(formElementSummaryNames[i] + ': ' + errorMessages[j++]); - } - }); - }); - }); // Directive() - - describe('When clicking on top menu Angular-Validation >> Service', function () { - it('Should navigate to TestingFormService page', function () { - browser.get('http://localhost/Github/angular-validation'); - - var anchorLink = $('[name=btn_goto_service]'); - anchorLink.click(); - browser.waitForAngular(); - - // Find the sub-title element - var titleElement = element(by.css('h3')); - expect(titleElement.getText()).toEqual('Service'); - }); - - it('Should have multiple form elements with all english labels', function () { - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - var elmLabel = $('label[for=' + formElementNames[i] + ']'); - expect(elmLabel.getText()).toEqual(formElementTexts[i]); - } - }); - - it('Should click and blur on each form elements and error message should display on each of them', function () { - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - // some fields are not required or disabled so no error will show up, continue to next ones - if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { - continue; - } - var elmInput = $('[name=' + formElementNames[i] + ']'); - elmInput.click(); - elmInput.sendKeys(protractor.Key.TAB); - - browser.waitForAngular(); - - if (formElementNames[i] === 'select1') { - element(by.cssContainingText('option', 'en')).click(); // click on good option first - element(by.cssContainingText('option', '...')).click(); // then click on option[0], the one containing '...' - elmInput.sendKeys(protractor.Key.TAB); + }); + + it('Should reload english route, click on submit and display all error messages', function () { + // scroll back to top if we want to be able to click on the English button + browser.executeScript('window.scrollTo(0,0);').then(function () { + var elmBtnEnglish = $('button[name=btn_english]'); + elmBtnEnglish.click(); + browser.waitForAngular(); + + var elmBtnNgSubmit = $('button[name=btn_ngSubmit]'); + elmBtnNgSubmit.click(); + browser.waitForAngular(); + + for (var i = 0, ln = formElementNames.length; i < ln; i++) { + // some fields are not required or disabled so no error will show up, continue to next ones + if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { + continue; + } + var elmError = $('.validation-' + formElementNames[i]); + expect(elmError.getText()).toEqual(errorMessages[i]); + } + }); + }); + + it('Should show ValidationSummary and contain all error messages', function () { + var elmBtnEnglish = $('button[name=btn_english]'); + elmBtnEnglish.click(); browser.waitForAngular(); - // browser.sleep(5000); // sleep 5 seconds - - var elmError = $('.validation-select1'); - expect(elmError.getText()).toEqual(errorMessages[i]); - continue; - } - - var elmError = $('.validation-' + formElementNames[i]); - expect(elmError.getText()).toEqual(errorMessages[i]); - } - }); - - it('Should click on removeValidator2 button blur input2 and make sure there is no error', function () { - // scroll back to top if we want to be able to click on the English button - browser.executeScript('window.scrollTo(0,0);').then(function () { - var elmInput = $('[name=input2]'); - elmInput.click(); - elmInput.sendKeys(protractor.Key.TAB); - - var elmError = $('.validation-input2'); - expect(elmError.getText()).toEqual(errorMessages[0]); - - var elmBtnRemoveValidator2 = $('button[name=btn_RemoveValidator2]'); - elmBtnRemoveValidator2.click(); - browser.waitForAngular(); - - elmError = $('.validation-input2'); - expect(elmError.getText()).toEqual(''); - }); - }); - - it('Should enter valid text and make error go away', function () { - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - // some fields are not required or disabled so no error will show up, continue to next ones - if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { - continue; - } - var elmInput = $('[name=' + formElementNames[i] + ']'); - elmInput.click(); - elmInput.sendKeys(validInputTexts[i]); - //elmInput.sendKeys(protractor.Key.TAB); - - if (formElementNames[i] === 'select1') { - element(by.cssContainingText('option', validInputTexts[i])).click(); // click on good option - elmInput.sendKeys(protractor.Key.TAB); - } - var elmError = $('.validation-' + formElementNames[i]); - expect(elmError.getText()).toEqual(''); - } - }); + // showValidation checkbox should false at first but true after + var elmCheckboxShowSummary = element(by.model('displayValidationSummary')); + expect(elmCheckboxShowSummary.isSelected()).toBeFalsy(); - it('Should reload english route, click on submit and display all error messages', function () { - // scroll back to top if we want to be able to click on the English button - browser.executeScript('window.scrollTo(0,0);').then(function () { - var elmBtnEnglish = $('button[name=btn_english]'); - elmBtnEnglish.click(); - browser.waitForAngular(); - - var elmBtnNgSubmit = $('button[name=btn_ngSubmit]'); - elmBtnNgSubmit.click(); - browser.waitForAngular(); - - for (var i = 0, ln = formElementNames.length; i < ln; i++) { - // some fields are not required or disabled so no error will show up, continue to next ones - if (formElementNames[i] === 'input12' || formElementNames[i] === 'input14') { - continue; - } - var elmError = $('.validation-' + formElementNames[i]); - expect(elmError.getText()).toEqual(errorMessages[i]); - } - }); - }); - - it('Should show ValidationSummary and contain all error messages', function () { - var elmBtnEnglish = $('button[name=btn_english]'); - elmBtnEnglish.click(); - browser.waitForAngular(); - - // showValidation checkbox should false at first but true after - var elmCheckboxShowSummary = element(by.model('displayValidationSummary')); - expect(elmCheckboxShowSummary.isSelected()).toBeFalsy(); - - var btnShowSummary = $('button[name=btn_showValidation]'); - btnShowSummary.click(); - browser.waitForAngular(); - - elmCheckboxShowSummary = element(by.model('displayValidationSummary')); - expect(elmCheckboxShowSummary.isSelected()).toBeTruthy(); - - // scroll back to top - browser.executeScript('window.scrollTo(0,0);').then(function () { - var itemRows = element.all(by.binding('message')); - var inputName; + var btnShowSummary = $('button[name=btn_showValidation]'); + btnShowSummary.click(); + browser.waitForAngular(); - for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) { - // since field after input13 is part of errorMessages and is empty string, we need to skip that one - if (formElementNames[i] === 'input13') { - j++; - } - expect(itemRows.get(i).getText()).toEqual(formElementSummaryNames[i] + ': ' + errorMessages[j++]); - } - }); - }); - }); // Service() + elmCheckboxShowSummary = element(by.model('displayValidationSummary')); + expect(elmCheckboxShowSummary.isSelected()).toBeTruthy(); + + // scroll back to top + browser.executeScript('window.scrollTo(0,0);').then(function () { + var itemRows = element.all(by.binding('message')); + var inputName; + + for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) { + // since field after input13 is part of errorMessages and is empty string, we need to skip that one + if (formElementNames[i] === 'input13') { + j++; + } + expect(itemRows.get(i).getText()).toEqual(formElementSummaryNames[i] + ': ' + errorMessages[j++]); + } + }); + }); + }); // Directive() + })(types, k); // closure + } // for() }); \ No newline at end of file diff --git a/readme.md b/readme.md index f49e09d..4ddc795 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ #Angular Validation (Directive / Service) -`Version: 1.3.24` +`Version: 1.3.25` ### Form validation after user inactivity of default 1sec. (customizable timeout) Forms Validation with Angular made easy! Angular-Validation is an angular directive/service with locales (languages) with a very simple approach of defining your `validation=""` directly within your element to validate (input, textarea, etc) and...that's it!!! The directive/service will take care of the rest! @@ -24,7 +24,7 @@ If you do use Angular-Validation, please click on the **Star** and add it as a f [Plunker](http://plnkr.co/jADq7H) ## Tested with Protractor -Angular-validation is now fully tested with Protractor End-to-End test suite, there is over 1000+ assertions, it starts by testing the original live demo page and then goes with a complete and full tests of All Validators in both the Angular-Validation Directive and Service. +Angular-validation is now has a full set of End-to-End tests with Protractor, there is over 1000+ assertions, it starts by testing the original live demo page and then goes with a complete and full test suite of All Validators in both the Angular-Validation Directive and Service. Why use angular-validation? @@ -73,6 +73,8 @@ All the documentation has been moved to the Wiki section, see the [github wiki]( * [Service Examples](https://github.com/ghiscoding/angular-validation/wiki/Working-Service-Examples) * [Alternate Text on Validators](https://github.com/ghiscoding/angular-validation/wiki/Alternate-Text-on-Validators) * [DisplayErrorTo](https://github.com/ghiscoding/angular-validation/wiki/Bootstrap-Input-Groups-Wrapping) + * [Remote Validation](https://github.com/ghiscoding/angular-validation/wiki/Remote-Validation) + * [Remove a Validator](https://github.com/ghiscoding/angular-validation/wiki/Remove-Validator-from-Element) * [Submit and Validation](https://github.com/ghiscoding/angular-validation/wiki/Form-Submit-and-Validation) * [Validation Summary](https://github.com/ghiscoding/angular-validation/wiki/Validation-Summary) * Validators diff --git a/src/validation-common.js b/src/validation-common.js index b66b249..3db6cac 100644 --- a/src/validation-common.js +++ b/src/validation-common.js @@ -361,6 +361,50 @@ angular var otherNgModelVal = self.scope.$eval(otherNgModel); isValid = (otherNgModelVal === strValue && !!strValue); } + // it might be a remote validation, this should return a promise with the result as a boolean or a { isValid: bool, message: msg } + else if(validator.type === "remote" && strValue !== '') { + //isValid = false; // make sure to invalidate the field so that the Directive/Service itself does not make it as true even though Remote might not be finished. + self.ctrl.$processing = true; // $processing can be use in the DOM to display a remote processing message to the user + + var fname = validator.params[0]; + var fn = self.scope[fname]; + var promise = (typeof fn === "function") ? fn() : null; + + if(!!promise && typeof promise.then === "function") { + self.ctrl.$setValidity('remote', false); // make the field invalid before processing it + + // process the promise + (function(altText) { + promise.then(function (result) { + self.ctrl.$processing = false; // finished resolving, no more pending + var errorMsg = message + ' '; // use the global error message + + if (typeof result === "boolean") { + isValid = (!!result) ? true : false; + }else if(typeof result === "object") { + isValid = (!!result.isValid) ? true : false; + } + + if(isValid === false) { + formElmObj.isValid = false; + errorMsg += (!!result.message) ? result.message : altText; + + // is field is invalid and we have an error message given, then add it to validationSummary and display error + addToValidationAndDisplayError(self, formElmObj, errorMsg, false, showError); + } + if(isValid === true && isFieldValid === true) { + // if field is valid from the remote check (isValid) and from the other validators check (isFieldValid) + // clear up the error message and make the field directly as Valid with $setValidity since remote check arrive after all other validators check + formElmObj.isValid = true; + self.ctrl.$setValidity('remote', true); + addToValidationAndDisplayError(self, formElmObj, '', true, showError); + } + }); + })(validator.altText); + }else { + throw 'Remote Validation requires a declared function (in your Controller) which also returns a promise, please review your code.' + } + } // or finally it might be a regular regex pattern checking else { // a 'disabled' element should always be valid, there is no need to validate it diff --git a/src/validation-rules.js b/src/validation-rules.js index d3616cc..a8bf782 100644 --- a/src/validation-rules.js +++ b/src/validation-rules.js @@ -525,6 +525,13 @@ angular type: "regex" }; break; + case "remote" : + validator = { + message: '', // there is no error message defined on this one since user will provide his own error message via remote response or `alt=` + params: [ruleParams], + type: "remote" + }; + break; case "required" : validator = { pattern: "\\S+", diff --git a/templates/testingFormDirective.html b/templates/testingFormDirective.html index a4bdc85..2d7567c 100644 --- a/templates/testingFormDirective.html +++ b/templates/testingFormDirective.html @@ -17,6 +17,10 @@

{{ 'ERRORS' | translate }}!

+
+ + +
diff --git a/templates/testingFormService.html b/templates/testingFormService.html index 9983ab8..ed79708 100644 --- a/templates/testingFormService.html +++ b/templates/testingFormService.html @@ -22,6 +22,10 @@

{{ 'ERRORS' | translate }}!

+
+ + +