diff --git a/API.md b/API.md
index 0e60eea..735feb8 100644
--- a/API.md
+++ b/API.md
@@ -306,6 +306,17 @@ Easily disable success/error message
}]);
```
+### **Allow empty values to pass regex validation**
+`default: false`
+To allow empty values to pass regex validation (such as: number) set allowEmptyValues to true.
+This way (unlike the default behaviour), an empty input would pass a "number" validation. (same as HTML5 number input)
+
+```javascript
+.config(['$validationProvider', function ($validationProvider) {
+ $validationProvider.allowEmptyValues = true; // or false(default)
+}]);
+```
+
### **Multiple validators**
Use commas to separate multiple validators.
diff --git a/dist/angular-validation.js b/dist/angular-validation.js
index 34f394e..1a9650d 100644
--- a/dist/angular-validation.js
+++ b/dist/angular-validation.js
@@ -160,6 +160,18 @@ angular.module('validation.directive', ['validation.provider']);
*/
this.showErrorMessage = true;
+ /**
+ * Whether to allow for empty values to pass validation.
+ * When true, empty values will pass regex validations such as 'number' (vacuous truth).
+ * This will comply with the w3 specs for number validation.
+ * Otherwise, empty values will fail the regex validation (default).
+ * You can easily change this to true in your config
+ * example: $validationProvider.allowEmptyValues = true;
+ *
+ * @type {boolean}
+ */
+ this.allowEmptyValues = false;
+
/**
* Check form valid, return true
* checkValid(Form): Check the specific form(Form) valid from angular `$valid`
@@ -308,6 +320,7 @@ angular.module('validation.directive', ['validation.provider']);
getDefaultMsg: this.getDefaultMsg,
showSuccessMessage: this.showSuccessMessage,
showErrorMessage: this.showErrorMessage,
+ allowEmptyValues: this.allowEmptyValues,
checkValid: this.checkValid,
validate: this.validate,
validCallback: this.validCallback,
@@ -603,8 +616,8 @@ angular.module('validation.directive', ['validation.provider']);
// Check with RegExp
else if (expression.constructor === RegExp) {
- // Only apply the test if the value is neither undefined or null
- if (value !== undefined && value !== null) {
+ // Only apply the test if the value is defined
+ if (value) {
if ($validationProvider.getExpression(validator).test(value)) {
if (validationGroup) {
groups[validationGroup][ctrl.$name] = true;
@@ -623,7 +636,8 @@ angular.module('validation.directive', ['validation.provider']);
return valid.error();
}
} else return valid.error();
- }
+ // if the value is empty or undefined, regex pass as vacuous truth
+ } else return $validationProvider.allowEmptyValues ? valid.success() : valid.error();
} else return valid.error();
};
diff --git a/dist/angular-validation.min.js b/dist/angular-validation.min.js
index 4d75ee0..ff163be 100644
--- a/dist/angular-validation.min.js
+++ b/dist/angular-validation.min.js
@@ -1 +1 @@
-angular.module("validation",["validation.provider","validation.directive"]),angular.module("validation.provider",[]),angular.module("validation.directive",["validation.provider"]),function(){function a(){var a,b,c,d,e,f=this,g=function(f){a=f,b=a.get("$rootScope"),c=a.get("$http"),d=a.get("$q"),e=a.get("$timeout")},h={},i=null,j={};this.setExpression=function(a){return angular.extend(h,a),f},this.getExpression=function(a){return h[a]},this.setDefaultMsg=function(a){return angular.extend(j,a),f},this.getDefaultMsg=function(a){return j[a]},this.setValidMethod=function(a){i=a},this.getValidMethod=function(){return i},this.setErrorHTML=function(a){if(a.constructor===Function)return f.getErrorHTML=a,f},this.getErrorHTML=function(a){return'
'+a+"
"},this.setSuccessHTML=function(a){if(a.constructor===Function)return f.getSuccessHTML=a,f},this.getSuccessHTML=function(a){return''+a+"
"},this.showSuccessMessage=!0,this.showErrorMessage=!0,this.checkValid=function(a){return!(!a||!a.$valid)},this.validate=function(a){var c=d.defer(),g=0;if(void 0===a)return console.error("This is not a regular Form name scope"),c.reject("This is not a regular Form name scope"),c.promise;if(a.validationId)b.$broadcast(a.$name+"submit-"+a.validationId,g++);else if(a.constructor===Array)for(var h in a)b.$broadcast(a[h].$name+"submit-"+a[h].validationId,g++);else for(var i in a)"$"!==i[0]&&a[i].hasOwnProperty("$dirty")&&b.$broadcast(i+"submit-"+a[i].validationId,g++);return c.promise.success=function(a){return c.promise.then(function(b){a(b)}),c.promise},c.promise.error=function(a){return c.promise.then(null,function(b){a(b)}),c.promise},e(function(){f.checkValid(a)?c.resolve("success"):c.reject("error")}),c.promise},this.validCallback=null,this.invalidCallback=null,this.resetCallback=null,this.reset=function(a){if(void 0===a)return void console.error("This is not a regular Form name scope");if(a.validationId)b.$broadcast(a.$name+"reset-"+a.validationId);else if(a.constructor===Array)for(var c in a)b.$broadcast(a[c].$name+"reset-"+a[c].validationId);else for(var d in a)"$"!==d[0]&&a[d].hasOwnProperty("$dirty")&&b.$broadcast(d+"reset-"+a[d].validationId)},this.addMsgElement=function(a){return a.after("")},this.getMsgElement=function(a){return a.next()},this.$get=["$injector",function(a){return g(a),{setValidMethod:this.setValidMethod,getValidMethod:this.getValidMethod,setErrorHTML:this.setErrorHTML,getErrorHTML:this.getErrorHTML,setSuccessHTML:this.setSuccessHTML,getSuccessHTML:this.getSuccessHTML,setExpression:this.setExpression,getExpression:this.getExpression,setDefaultMsg:this.setDefaultMsg,getDefaultMsg:this.getDefaultMsg,showSuccessMessage:this.showSuccessMessage,showErrorMessage:this.showErrorMessage,checkValid:this.checkValid,validate:this.validate,validCallback:this.validCallback,invalidCallback:this.invalidCallback,resetCallback:this.resetCallback,reset:this.reset,addMsgElement:this.addMsgElement,getMsgElement:this.getMsgElement}}]}angular.module("validation.provider").provider("$validation",a)}.call(this),function(){function a(a){var b=a.get("$validation"),c=a.get("$timeout"),d=a.get("$parse");return{link:function(a,e,f){var g=d(f.validationReset)(a);c(function(){e.on("click",function(a){a.preventDefault(),b.reset(g)})})}}}angular.module("validation.directive").directive("validationReset",a),a.$inject=["$injector"]}.call(this),function(){function a(a){var b=a.get("$validation"),c=a.get("$timeout"),d=a.get("$parse");return{priority:1,require:"?ngClick",link:function(a,e,f){var g=d(f.validationSubmit)(a);c(function(){e.off("click"),e.on("click",function(c){c.preventDefault(),b.validate(g).success(function(){d(f.ngClick)(a)})})})}}}angular.module("validation.directive").directive("validationSubmit",a),a.$inject=["$injector"]}.call(this),function(){function a(a){function b(a,b,c){for(var d=document.querySelectorAll("*[validation-group="+b+"]"),e=0,f=d.length;e0?(b=a[0],angular.isObject(b)||(b={result:b,message:""})):b={result:!1,message:""},b}var d=a.get("$validation"),e=a.get("$q"),f=a.get("$timeout"),g=a.get("$compile"),h=a.get("$parse"),i={},j=function(a,b,c,e,f,i){var j,k=b||d.getDefaultMsg(c).success,l=h(i.validCallback),m=i.messageId,n=i.validationGroup;return j=m||n?angular.element(document.querySelector("#"+(m||n))):d.getMsgElement(a),a.attr("no-validation-message")?j.css("display","none"):d.showSuccessMessage&&k?(j.html("").append(g(d.getSuccessHTML(k,a,i))(e)),j.css("display","")):j.css("display","none"),f.$setValidity(f.$name,!0),l(e,{message:k}),d.validCallback&&d.validCallback(a),!0},k=function(a,b,c,e,f,i){var j,k=b||d.getDefaultMsg(c).error,l=h(i.invalidCallback),m=i.messageId,n=i.validationGroup;return j=m||n?angular.element(document.querySelector("#"+(m||n))):d.getMsgElement(a),a.attr("no-validation-message")?j.css("display","none"):d.showErrorMessage&&k?(j.html("").append(g(d.getErrorHTML(k,a,i))(e)),j.css("display","")):j.css("display","none"),f.$setValidity(f.$name,!1),l(e,{message:k}),d.invalidCallback&&d.invalidCallback(a),!1},l=function(a){var b=i[a];return Object.keys(b).some(function(a){return b[a]})},m={},n=function(a,f,g,h,m,o){var p=m.slice(0),q=p[0].trim(),r=q.indexOf("="),s=r===-1?q:q.substr(0,r),t=r===-1?null:q.substr(r+1),u=p.slice(1),v=s+"SuccessMessage",w=s+"ErrorMessage",x=d.getExpression(s),y=g.validationGroup,z={success:function(b){return j(f,b||g[v],s,a,h,g),!u.length||n(a,f,g,h,u,o)},error:function(b){return k(f,b||g[w],s,a,h,g)}};if(void 0===x)return console.error('You are using undefined validator "%s"',s),u.length?n(a,f,g,h,u,o):void 0;if(x.constructor===Function)return e.all([d.getExpression(s)(o,a,f,g,t)]).then(function(d){var e=c(d),f=e.message;return e.result?(y&&(i[y][h.$name]=!0,b(a,y,!0)),z.success(f)):y?(i[y][h.$name]=!1,l(y)?void b(a,y,!0):(b(a,y,!1),z.error(f))):z.error(f)},function(){return z.error()});if(x.constructor!==RegExp)return z.error();if(void 0!==o&&null!==o){if(d.getExpression(s).test(o))return y&&(i[y][h.$name]=!0,b(a,y,!0)),z.success();if(!y)return z.error();if(i[y][h.$name]=!1,!l(y))return b(a,y,!1),z.error();b(a,y,!0)}},o=function(){return(65536*(1+Math.random())|0).toString(16).substring(1)},p=function(){return o()+o()+o()+o()};return{restrict:"A",require:"ngModel",link:function(a,b,c,e){var g,h=c.validator,j=c.messageId,k=c.validationGroup,l=c.validMethod,o=c.ngModel,q=function(){},r=h.split(","),s=e.validationId=p(),t=null;return"boolean"==typeof a.initialValidity&&(g=a.initialValidity),k&&(i[k]||(i[k]={}),i[k][e.$name]=!1),j||k||d.addMsgElement(b),e.$setValidity(e.$name,g),a.$on(e.$name+"reset-"+s,function(){q(),f(function(){e.$setViewValue(t),e.$setPristine(),e.$setValidity(e.$name,void 0),e.$render(),j||k?angular.element(document.querySelector("#"+(j||k))).html(""):d.getMsgElement(b).html(""),d.resetCallback&&d.resetCallback(b)})}),l=angular.isUndefined(l)?d.getValidMethod():l,a.$on(e.$name+"submit-"+s,function(d,g){var h=e.$viewValue,i=!1;i=n(a,b,c,e,r,h),"submit"===l&&(q(),q=a.$watch(function(){return a.$eval(o)},function(d,f){d!==f&&(void 0!==d&&null!==d||(d=""),i=n(a,b,c,e,r,d))}));var j=function(a){a?delete m[g]:(m[g]=b[0],f(function(){m[Math.min.apply(null,Object.keys(m))].focus()},0))};i.constructor===Object?i.then(j):j(i)}),"blur"===l?void b.bind("blur",function(){var d=a.$eval(o);a.$apply(function(){n(a,b,c,e,r,d)})}):void("submit"!==l&&"submit-only"!==l&&(a.$watch(function(){return a.$eval(o)},function(f){if(e.$pristine&&e.$viewValue)t=e.$viewValue||"",e.$setViewValue(e.$viewValue);else if(e.$pristine)return void(j||k?angular.element(document.querySelector("#"+(j||k))).html(""):d.getMsgElement(b).html(""));n(a,b,c,e,r,f)}),f(function(){c.$observe("noValidationMessage",function(a){var c;c=j||k?angular.element(document.querySelector("#"+(j||k))):d.getMsgElement(b),"true"===a||a===!0?c.css("display","none"):"false"!==a&&a!==!1||c.css("display","block")})})))}}}angular.module("validation.directive").directive("validator",a),a.$inject=["$injector"]}.call(this);
\ No newline at end of file
+angular.module("validation",["validation.provider","validation.directive"]),angular.module("validation.provider",[]),angular.module("validation.directive",["validation.provider"]),function(){function a(){var a,b,c,d,e,f=this,g=function(f){a=f,b=a.get("$rootScope"),c=a.get("$http"),d=a.get("$q"),e=a.get("$timeout")},h={},i=null,j={};this.setExpression=function(a){return angular.extend(h,a),f},this.getExpression=function(a){return h[a]},this.setDefaultMsg=function(a){return angular.extend(j,a),f},this.getDefaultMsg=function(a){return j[a]},this.setValidMethod=function(a){i=a},this.getValidMethod=function(){return i},this.setErrorHTML=function(a){if(a.constructor===Function)return f.getErrorHTML=a,f},this.getErrorHTML=function(a){return''+a+"
"},this.setSuccessHTML=function(a){if(a.constructor===Function)return f.getSuccessHTML=a,f},this.getSuccessHTML=function(a){return''+a+"
"},this.showSuccessMessage=!0,this.showErrorMessage=!0,this.allowEmptyValues=!1,this.checkValid=function(a){return!(!a||!a.$valid)},this.validate=function(a){var c=d.defer(),g=0;if(void 0===a)return console.error("This is not a regular Form name scope"),c.reject("This is not a regular Form name scope"),c.promise;if(a.validationId)b.$broadcast(a.$name+"submit-"+a.validationId,g++);else if(a.constructor===Array)for(var h in a)b.$broadcast(a[h].$name+"submit-"+a[h].validationId,g++);else for(var i in a)"$"!==i[0]&&a[i].hasOwnProperty("$dirty")&&b.$broadcast(i+"submit-"+a[i].validationId,g++);return c.promise.success=function(a){return c.promise.then(function(b){a(b)}),c.promise},c.promise.error=function(a){return c.promise.then(null,function(b){a(b)}),c.promise},e(function(){f.checkValid(a)?c.resolve("success"):c.reject("error")}),c.promise},this.validCallback=null,this.invalidCallback=null,this.resetCallback=null,this.reset=function(a){if(void 0===a)return void console.error("This is not a regular Form name scope");if(a.validationId)b.$broadcast(a.$name+"reset-"+a.validationId);else if(a.constructor===Array)for(var c in a)b.$broadcast(a[c].$name+"reset-"+a[c].validationId);else for(var d in a)"$"!==d[0]&&a[d].hasOwnProperty("$dirty")&&b.$broadcast(d+"reset-"+a[d].validationId)},this.addMsgElement=function(a){return a.after("")},this.getMsgElement=function(a){return a.next()},this.$get=["$injector",function(a){return g(a),{setValidMethod:this.setValidMethod,getValidMethod:this.getValidMethod,setErrorHTML:this.setErrorHTML,getErrorHTML:this.getErrorHTML,setSuccessHTML:this.setSuccessHTML,getSuccessHTML:this.getSuccessHTML,setExpression:this.setExpression,getExpression:this.getExpression,setDefaultMsg:this.setDefaultMsg,getDefaultMsg:this.getDefaultMsg,showSuccessMessage:this.showSuccessMessage,showErrorMessage:this.showErrorMessage,allowEmptyValues:this.allowEmptyValues,checkValid:this.checkValid,validate:this.validate,validCallback:this.validCallback,invalidCallback:this.invalidCallback,resetCallback:this.resetCallback,reset:this.reset,addMsgElement:this.addMsgElement,getMsgElement:this.getMsgElement}}]}angular.module("validation.provider").provider("$validation",a)}.call(this),function(){function a(a){var b=a.get("$validation"),c=a.get("$timeout"),d=a.get("$parse");return{link:function(a,e,f){var g=d(f.validationReset)(a);c(function(){e.on("click",function(a){a.preventDefault(),b.reset(g)})})}}}angular.module("validation.directive").directive("validationReset",a),a.$inject=["$injector"]}.call(this),function(){function a(a){var b=a.get("$validation"),c=a.get("$timeout"),d=a.get("$parse");return{priority:1,require:"?ngClick",link:function(a,e,f){var g=d(f.validationSubmit)(a);c(function(){e.off("click"),e.on("click",function(c){c.preventDefault(),b.validate(g).success(function(){d(f.ngClick)(a)})})})}}}angular.module("validation.directive").directive("validationSubmit",a),a.$inject=["$injector"]}.call(this),function(){function a(a){function b(a,b,c){for(var d=document.querySelectorAll("*[validation-group="+b+"]"),e=0,f=d.length;e0?(b=a[0],angular.isObject(b)||(b={result:b,message:""})):b={result:!1,message:""},b}var d=a.get("$validation"),e=a.get("$q"),f=a.get("$timeout"),g=a.get("$compile"),h=a.get("$parse"),i={},j=function(a,b,c,e,f,i){var j,k=b||d.getDefaultMsg(c).success,l=h(i.validCallback),m=i.messageId,n=i.validationGroup;return j=m||n?angular.element(document.querySelector("#"+(m||n))):d.getMsgElement(a),a.attr("no-validation-message")?j.css("display","none"):d.showSuccessMessage&&k?(j.html("").append(g(d.getSuccessHTML(k,a,i))(e)),j.css("display","")):j.css("display","none"),f.$setValidity(f.$name,!0),l(e,{message:k}),d.validCallback&&d.validCallback(a),!0},k=function(a,b,c,e,f,i){var j,k=b||d.getDefaultMsg(c).error,l=h(i.invalidCallback),m=i.messageId,n=i.validationGroup;return j=m||n?angular.element(document.querySelector("#"+(m||n))):d.getMsgElement(a),a.attr("no-validation-message")?j.css("display","none"):d.showErrorMessage&&k?(j.html("").append(g(d.getErrorHTML(k,a,i))(e)),j.css("display","")):j.css("display","none"),f.$setValidity(f.$name,!1),l(e,{message:k}),d.invalidCallback&&d.invalidCallback(a),!1},l=function(a){var b=i[a];return Object.keys(b).some(function(a){return b[a]})},m={},n=function(a,f,g,h,m,o){var p=m.slice(0),q=p[0].trim(),r=q.indexOf("="),s=r===-1?q:q.substr(0,r),t=r===-1?null:q.substr(r+1),u=p.slice(1),v=s+"SuccessMessage",w=s+"ErrorMessage",x=d.getExpression(s),y=g.validationGroup,z={success:function(b){return j(f,b||g[v],s,a,h,g),!u.length||n(a,f,g,h,u,o)},error:function(b){return k(f,b||g[w],s,a,h,g)}};return void 0===x?(console.error('You are using undefined validator "%s"',s),u.length?n(a,f,g,h,u,o):void 0):x.constructor===Function?e.all([d.getExpression(s)(o,a,f,g,t)]).then(function(d){var e=c(d),f=e.message;return e.result?(y&&(i[y][h.$name]=!0,b(a,y,!0)),z.success(f)):y?(i[y][h.$name]=!1,l(y)?void b(a,y,!0):(b(a,y,!1),z.error(f))):z.error(f)},function(){return z.error()}):x.constructor!==RegExp?z.error():o?d.getExpression(s).test(o)?(y&&(i[y][h.$name]=!0,b(a,y,!0)),z.success()):y?(i[y][h.$name]=!1,l(y)?void b(a,y,!0):(b(a,y,!1),z.error())):z.error():d.allowEmptyValues?z.success():z.error()},o=function(){return(65536*(1+Math.random())|0).toString(16).substring(1)},p=function(){return o()+o()+o()+o()};return{restrict:"A",require:"ngModel",link:function(a,b,c,e){var g,h=c.validator,j=c.messageId,k=c.validationGroup,l=c.validMethod,o=c.ngModel,q=function(){},r=h.split(","),s=e.validationId=p(),t=null;return"boolean"==typeof a.initialValidity&&(g=a.initialValidity),k&&(i[k]||(i[k]={}),i[k][e.$name]=!1),j||k||d.addMsgElement(b),e.$setValidity(e.$name,g),a.$on(e.$name+"reset-"+s,function(){q(),f(function(){e.$setViewValue(t),e.$setPristine(),e.$setValidity(e.$name,void 0),e.$render(),j||k?angular.element(document.querySelector("#"+(j||k))).html(""):d.getMsgElement(b).html(""),d.resetCallback&&d.resetCallback(b)})}),l=angular.isUndefined(l)?d.getValidMethod():l,a.$on(e.$name+"submit-"+s,function(d,g){var h=e.$viewValue,i=!1;i=n(a,b,c,e,r,h),"submit"===l&&(q(),q=a.$watch(function(){return a.$eval(o)},function(d,f){d!==f&&(void 0!==d&&null!==d||(d=""),i=n(a,b,c,e,r,d))}));var j=function(a){a?delete m[g]:(m[g]=b[0],f(function(){m[Math.min.apply(null,Object.keys(m))].focus()},0))};i.constructor===Object?i.then(j):j(i)}),"blur"===l?void b.bind("blur",function(){var d=a.$eval(o);a.$apply(function(){n(a,b,c,e,r,d)})}):void("submit"!==l&&"submit-only"!==l&&(a.$watch(function(){return a.$eval(o)},function(f){if(e.$pristine&&e.$viewValue)t=e.$viewValue||"",e.$setViewValue(e.$viewValue);else if(e.$pristine)return void(j||k?angular.element(document.querySelector("#"+(j||k))).html(""):d.getMsgElement(b).html(""));n(a,b,c,e,r,f)}),f(function(){c.$observe("noValidationMessage",function(a){var c;c=j||k?angular.element(document.querySelector("#"+(j||k))):d.getMsgElement(b),"true"===a||a===!0?c.css("display","none"):"false"!==a&&a!==!1||c.css("display","block")})})))}}}angular.module("validation.directive").directive("validator",a),a.$inject=["$injector"]}.call(this);
\ No newline at end of file
diff --git a/src/provider.js b/src/provider.js
index 6dc7cda..eb8054e 100644
--- a/src/provider.js
+++ b/src/provider.js
@@ -156,6 +156,18 @@
*/
this.showErrorMessage = true;
+ /**
+ * Whether to allow for empty values to pass validation.
+ * When true, empty values will pass regex validations such as 'number' (vacuous truth).
+ * This will comply with the w3 specs for number validation.
+ * Otherwise, empty values will fail the regex validation (default).
+ * You can easily change this to true in your config
+ * example: $validationProvider.allowEmptyValues = true;
+ *
+ * @type {boolean}
+ */
+ this.allowEmptyValues = false;
+
/**
* Check form valid, return true
* checkValid(Form): Check the specific form(Form) valid from angular `$valid`
@@ -304,6 +316,7 @@
getDefaultMsg: this.getDefaultMsg,
showSuccessMessage: this.showSuccessMessage,
showErrorMessage: this.showErrorMessage,
+ allowEmptyValues: this.allowEmptyValues,
checkValid: this.checkValid,
validate: this.validate,
validCallback: this.validCallback,
diff --git a/src/validator.directive.js b/src/validator.directive.js
index 5b39e50..f120cec 100644
--- a/src/validator.directive.js
+++ b/src/validator.directive.js
@@ -225,8 +225,8 @@
// Check with RegExp
else if (expression.constructor === RegExp) {
- // Only apply the test if the value is neither undefined or null
- if (value !== undefined && value !== null) {
+ // Only apply the test if the value is defined
+ if (value) {
if ($validationProvider.getExpression(validator).test(value)) {
if (validationGroup) {
groups[validationGroup][ctrl.$name] = true;
@@ -245,7 +245,8 @@
return valid.error();
}
} else return valid.error();
- }
+ // if the value is empty or undefined, regex pass as vacuous truth
+ } else return $validationProvider.allowEmptyValues ? valid.success() : valid.error();
} else return valid.error();
};
diff --git a/test/unit/actualValue.js b/test/unit/actualValue.js
index 6967131..6b8c7ac 100644
--- a/test/unit/actualValue.js
+++ b/test/unit/actualValue.js
@@ -2,7 +2,7 @@
/* jasmine specs for provider go here */
-describe('provider', function() {
+describe('provider with empty values disallowed', function() {
var $rootScope;
var $compile;
var $scope;
@@ -109,4 +109,50 @@ describe('provider', function() {
expect(successSpy).not.toHaveBeenCalled();
expect(errorSpy).toHaveBeenCalled();
}));
+
+ it('set value to undefined', inject(function() {
+ var submitSpy = jasmine.createSpy('submitSpy');
+ var successSpy = jasmine.createSpy('successSpy');
+ var errorSpy = jasmine.createSpy('errorSpy');
+
+ $scope.$apply(function() {
+ $scope.number = undefined;
+ });
+
+ // expect fail as a empty values are disallowed
+ validationProvider.validate($scope.Form)
+ .success(function() {
+ successSpy();
+ })
+ .error(function() {
+ errorSpy();
+ });
+
+ $timeout.flush();
+ expect(successSpy).not.toHaveBeenCalled();
+ expect(errorSpy).toHaveBeenCalled();
+ }));
+
+ it('set value to empty', inject(function() {
+ var submitSpy = jasmine.createSpy('submitSpy');
+ var successSpy = jasmine.createSpy('successSpy');
+ var errorSpy = jasmine.createSpy('errorSpy');
+
+ $scope.$apply(function() {
+ $scope.number = '';
+ });
+
+ // expect fail as a empty values are disallowed
+ validationProvider.validate($scope.Form)
+ .success(function() {
+ successSpy();
+ })
+ .error(function() {
+ errorSpy();
+ });
+
+ $timeout.flush();
+ expect(successSpy).not.toHaveBeenCalled();
+ expect(errorSpy).toHaveBeenCalled();
+ }));
});
diff --git a/test/unit/actualValueWithEmpty.js b/test/unit/actualValueWithEmpty.js
new file mode 100644
index 0000000..058f2cb
--- /dev/null
+++ b/test/unit/actualValueWithEmpty.js
@@ -0,0 +1,93 @@
+'use strict';
+
+/* jasmine specs for provider go here */
+
+describe('provider with empty values allowed', function() {
+ var $rootScope;
+ var $compile;
+ var $scope;
+ var $timeout;
+ var element;
+ var validationProvider;
+ var myApp;
+
+ beforeEach(function() {
+ myApp = angular.module('myApp', ['validation', 'validation.rule'])
+ .config(function($validationProvider) {
+ validationProvider = $validationProvider;
+ // Allow empty values
+ $validationProvider.allowEmptyValues = true;
+ });
+
+ return myApp;
+ });
+
+ beforeEach(module('myApp'));
+
+ beforeEach(inject(function($injector) {
+ $rootScope = $injector.get('$rootScope');
+ $compile = $injector.get('$compile');
+ $scope = $rootScope.$new();
+ $timeout = $injector.get('$timeout');
+
+ element = $compile('')($scope);
+ angular.element(document.body).append(element);
+ $scope.$digest();
+ }));
+
+ it('set value to undefined', inject(function() {
+ var submitSpy = jasmine.createSpy('submitSpy');
+ var successSpy = jasmine.createSpy('successSpy');
+ var errorSpy = jasmine.createSpy('errorSpy');
+
+ $scope.$apply(function() {
+ $scope.number = undefined;
+ });
+
+ $scope.$on('numberWatchsubmit-' + $scope.Form.numberWatch.validationId, function() {
+ submitSpy();
+ });
+
+ // expect success as a vacuous truth (value is undefined and should therefore pass both number and maxlength tests)
+ validationProvider.validate($scope.Form)
+ .success(function() {
+ successSpy();
+ })
+ .error(function() {
+ errorSpy();
+ });
+
+ $timeout.flush();
+ expect(submitSpy).toHaveBeenCalled();
+ expect(successSpy).toHaveBeenCalled();
+ expect(errorSpy).not.toHaveBeenCalled();
+ }));
+
+ it('set value to empty', inject(function() {
+ var submitSpy = jasmine.createSpy('submitSpy');
+ var successSpy = jasmine.createSpy('successSpy');
+ var errorSpy = jasmine.createSpy('errorSpy');
+
+ $scope.$apply(function() {
+ $scope.number = '';
+ });
+
+ $scope.$on('numberWatchsubmit-' + $scope.Form.numberWatch.validationId, function() {
+ submitSpy();
+ });
+
+ // expect success as a vacuous truth (value is empty and should therefore pass both number and maxlength tests)
+ validationProvider.validate($scope.Form)
+ .success(function() {
+ successSpy();
+ })
+ .error(function() {
+ errorSpy();
+ });
+
+ $timeout.flush();
+ expect(submitSpy).toHaveBeenCalled();
+ expect(successSpy).toHaveBeenCalled();
+ expect(errorSpy).not.toHaveBeenCalled();
+ }));
+});
diff --git a/test/unit/validationGroupSpec.js b/test/unit/validationGroupSpec.js
index 9a77b8a..4df78c3 100644
--- a/test/unit/validationGroupSpec.js
+++ b/test/unit/validationGroupSpec.js
@@ -154,8 +154,8 @@ describe('validation-group directive', function() {
it('should be dirty and invalid', function() {
$scope.Form.email.$setViewValue('foo@bar.com');
$scope.Form.telephone.$setViewValue('065839481');
- $scope.Form.email.$setViewValue('');
- $scope.Form.telephone.$setViewValue('');
+ $scope.Form.email.$setViewValue('aa');
+ $scope.Form.telephone.$setViewValue('aa');
expect($scope.Form.$dirty).toBe(true);
expect(element.hasClass('ng-dirty')).toBe(true);
@@ -169,11 +169,11 @@ describe('validation-group directive', function() {
expect(element.hasClass('ng-valid')).toBe(true);
$scope.Form.telephone.$setViewValue('065839481');
- $scope.Form.email.$setViewValue('');
+ $scope.Form.email.$setViewValue('a');
expect($scope.Form.$valid).toBe(true);
expect(element.hasClass('ng-valid')).toBe(true);
- $scope.Form.telephone.$setViewValue('');
+ $scope.Form.telephone.$setViewValue('aa');
expect($scope.Form.$valid).toBe(false);
expect(element.hasClass('ng-invalid')).toBe(true);
});
@@ -188,7 +188,7 @@ describe('validation-group directive', function() {
it('should have an error message inside the #contact element when no element is valid', function() {
$scope.Form.email.$setViewValue('foo@bar.com');
- $scope.Form.email.$setViewValue('');
+ $scope.Form.email.$setViewValue('a');
messageElem = angular.element(element[0].querySelector('#contact > p'));
expect(messageElem.hasClass('validation-invalid')).toBe(true);
@@ -205,7 +205,7 @@ describe('validation-group directive', function() {
it('should have a success message inside the #contact element when one of element is valid', function() {
$scope.Form.email.$setViewValue('foo@bar.com');
$scope.Form.telephone.$setViewValue('065839481');
- $scope.Form.email.$setViewValue('');
+ $scope.Form.email.$setViewValue('a');
messageElem = angular.element(element[0].querySelector('#contact > p'));
expect(messageElem.hasClass('validation-valid')).toBe(true);
@@ -214,8 +214,8 @@ describe('validation-group directive', function() {
it('should have an error message inside the #contact element when both of elements are invalid', function() {
$scope.Form.email.$setViewValue('foo@bar.com');
$scope.Form.telephone.$setViewValue('065839481');
- $scope.Form.email.$setViewValue('');
- $scope.Form.telephone.$setViewValue('');
+ $scope.Form.email.$setViewValue('a');
+ $scope.Form.telephone.$setViewValue('a');
messageElem = angular.element(element[0].querySelector('#contact > p'));
expect(messageElem.hasClass('validation-invalid')).toBe(true);