From 6733a96a70467b51bc821aa6ecbbc606ab973676 Mon Sep 17 00:00:00 2001 From: Alejandro Mostajo Date: Wed, 7 Sep 2016 17:51:01 -0600 Subject: [PATCH] Added validation rules. New validation ruless (equals, required_if and url) added. --- README.md | 21 ++++++----- dist/vue.form.js | 39 ++++++++++++++++++- dist/vue.form.min.js | 2 +- package.json | 2 +- src/vue.form.js | 39 ++++++++++++++++++- tests/test2.html | 90 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 tests/test2.html diff --git a/README.md b/README.md index 49c7721..cb8b819 100644 --- a/README.md +++ b/README.md @@ -364,15 +364,18 @@ List of available rules to use: Rule | Params | Sample | Description ---------------- | ------------------------------------------------ | ---------------------- | ----------- -`required` | | `required` | Validates that value is not empty. -`email` | | `email` | Validates that value has a valid email format. -`number` | | `number` | Validates that value is numeric. -`min` | 1) minimum string length | `min:2` | Validates that value's length is not lower than the minimum value set. -`min_number` | 1) minimum number | | `min_number:10` | Validates that value is not lower than the minimum value set. -`max` | 1) maximum string length | `max:10` | Validates that value's length is not bigger than the maximum value set. -`max_number` | 1) maximum number length | `max_number:15` | Validates that value is not bigger than the maximum value set. -`between` | 1) minimum string length 2) maximum string length | `between:5:10` | Validates that value's length is in between the number range set. -`between_number` | 1) minimum number 2) maximum number | `between_number:1:100` | Validates that value is in between the number range set. +`required` | | `required` | Validates if value is not empty. +`required_if` | 1) comparison field | `required_if:email` | Validates if value is not empty only if comparison field is not empty. +`email` | | `email` | Validates if value has a valid email format. +`number` | | `number` | Validates if value is numeric. +`min` | 1) minimum string length | `min:2` | Validates if value's length is not lower than the minimum value set. +`min_number` | 1) minimum number | `min_number:10` | Validates if value is not lower than the minimum value set. +`max` | 1) maximum string length | `max:10` | Validates if value's length is not bigger than the maximum value set. +`max_number` | 1) maximum number length | `max_number:15` | Validates if value is not bigger than the maximum value set. +`between` | 1) minimum string length 2) maximum string length | `between:5:10` | Validates if value's length is in between the number range set. +`between_number` | 1) minimum number 2) maximum number | `between_number:1:100` | Validates if value is in between the number range set. +`equals` | 1) comparison field | `equals:password` | Validates if value is the same as comparison field's value. +`url` | | `url` | Validates if value has a valid url format. ### Events diff --git a/dist/vue.form.js b/dist/vue.form.js index e9d586a..532a298 100644 --- a/dist/vue.form.js +++ b/dist/vue.form.js @@ -6,7 +6,7 @@ * @author Alejandro Mostajo * @copyright 10Quality * @license MIT - * @version 1.0.5 + * @version 1.0.7 */ Vue.component('vform', Vue.extend({ props: @@ -84,6 +84,7 @@ Vue.component('vform', Vue.extend({ /** * List of default errors. * @since 1.0.2 + * @since 1.0.7 Added equal,required_if,url * @var object */ errors: @@ -100,6 +101,9 @@ Vue.component('vform', Vue.extend({ max_number: 'Value must be no more than %1%.', between: 'Value must have between %1% to %2% characters.', between_number: 'Value must be between %1% to %2%.', + equals: 'Value must be equal to %1%.', + required_if: 'Required field.', + url: 'Url value is invalid.', }; }, }, @@ -396,6 +400,7 @@ Vue.component('vform', Vue.extend({ /** * Validates input. * @since 1.0.2 + * @since 1.0.7 Added equal,required_if,url * * @return bool */ @@ -499,6 +504,38 @@ Vue.component('vform', Vue.extend({ success = false; } break; + case 'equals': + if (options.length < 2) + throw 'Comparison field is not defined in validation rules'; + if (this.$parent.request[this.listen] !== undefined + && this.$parent.request[this.listen] !== this.$parent.request[options[1]] + ) { + this.addError(options); + success = false; + } + break; + case 'required_if': + if (options.length < 2) + throw 'Comparison field is not defined in validation rules'; + if (this.$parent.request[options[1]] !== undefined + && this.$parent.request[options[1]].length > 0 + && (this.$parent.request[this.listen] === undefined + || this.$parent.request[this.listen].length === 0 + ) + ) { + this.addError(options); + success = false; + } + break; + case 'url': + var regex = /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/; + if (this.$parent.request[this.listen] !== undefined + && !regex.test(this.$parent.request[this.listen]) + ) { + this.addError(options); + success = false; + } + break; } } return success; diff --git a/dist/vue.form.min.js b/dist/vue.form.min.js index 14dba6e..2b558f0 100644 --- a/dist/vue.form.min.js +++ b/dist/vue.form.min.js @@ -1 +1 @@ -"use strict";Vue.component("vform",Vue.extend({props:{action:{type:String,"default":""},method:{type:String,"default":"POST"},headers:{type:Object,"default":function(){}},timeout:{type:[String,Number],"default":void 0},credentials:{type:[String,Boolean],"default":void 0},emulateHttp:{type:[String,Boolean],"default":void 0},emulateJson:{type:[String,Boolean],"default":void 0},errors:{type:Object,"default":function(){return{required:"Required field.",number:"Value must be numeric.",email:"Email value is invalid.",min:"Value must have at least %1% character(s).",min_number:"Value must be at least %1%.",max:"Value must have no more than %1% character(s).",max_number:"Value must be no more than %1%.",between:"Value must have between %1% to %2% characters.",between_number:"Value must be between %1% to %2%."}}},id:{type:[String,Number],"default":void 0},key:{type:[String,Number],"default":void 0}},data:function(){return{request:{},isLoading:!1,response:{}}},computed:{hasMessage:function(){return void 0!=this.response.message},hasError:function(){return void 0!=this.response.error&&this.response.error}},methods:{submit:function(){var a=!0;this.$set("response",{});for(var b in this.$children)"function"==typeof this.$children[b].validate&&(a=this.$children[b].validate()&&a);a?(this.$set("isLoading",!0),this.$http(this.getOptions()).then(this.onSubmit,this.onError)):(this.$dispatch("vform_invalid",this.response.errors),this.$broadcast("vform_invalid",this.response.errors))},onSubmit:function(a){return this.$set("response",a.data),this.$dispatch("vform_success"),this.$broadcast("vform_success"),void 0!==this.response.errors&&Object.keys(this.response.errors).length>0&&(this.$dispatch("vform_invalid",this.response.errors),this.$broadcast("vform_invalid",this.response.errors)),void 0!==a.data.redirect?window.location=a.data.redirect:void this.onComplete()},onComplete:function(){this.$set("isLoading",!1),this.$dispatch("vform_complete"),this.$broadcast("vform_complete")},onError:function(a){console.log(a),this.$dispatch("vform_error",a),this.$broadcast("vform_error",a),this.onComplete()},getOptions:function(){var a={url:this.action,method:this.method};switch(void 0!==this.headers&&(a.headers=this.headers),void 0!==this.timeout&&(a.timeout=this.timeout),void 0!==this.credentials&&(a.credentials="boolean"==typeof this.credentials?this.credentials:"true"===this.credentials),void 0!==this.emulateHttp&&(a.emulateHTTP="boolean"==typeof this.emulateHttp?this.emulateHttp:"true"===this.emulateHttp),void 0!==this.emulateJson&&(a.emulateJSON="boolean"==typeof this.emulateJson?this.emulateJson:"true"===this.emulateJson),this.method){case"post":case"POST":case"put":case"PUT":case"patch":case"PATCH":a.body=this.request;break;default:a.params=this.request}return a}},components:{"input-handler":Vue.extend({template:'
  • {{error}}
',props:{listen:{type:String,"default":""},"class":{type:String,"default":""},classError:{type:String,"default":void 0},response:{type:[Object,Array],"default":function(){return{}}},validations:{type:String,"default":""}},computed:{inputErrors:function(){var a=[];return void 0!==this.response.errors&&void 0!==this.response.errors[this.listen]&&(a=this.response.errors[this.listen]),a},hasErrors:function(){return this.inputErrors.length>0},errorCss:function(){var a={};return void 0!==this.classError&&(a[this.classError]=this.hasErrors),a}},methods:{validate:function(){var a=!0,b=this.validations.split("|");for(var c in b){var d=b[c].split(":");switch(d[0]){case"required":void 0!==this.$parent.request[this.listen]&&0!==this.$parent.request[this.listen].length||(this.addError(d),a=!1);break;case"number":void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen].length>0&&isNaN(this.$parent.request[this.listen])&&(this.addError(d),a=!1);break;case"min":if(d.length<2)throw"Minimum value is not defined in validation rules";void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen].length>0&&this.$parent.request[this.listen].length0&&this.$parent.request[this.listen].length>parseInt(d[1])&&(this.addError(d),a=!1);break;case"max_number":if(d.length<2)throw"Minimum value is not defined in validation rules";void 0!==this.$parent.request[this.listen]&&parseInt(this.$parent.request[this.listen])>parseInt(d[1])&&(this.addError(d),a=!1);break;case"between":if(d.length<3)throw"One or all between values are not defined in validation rules";void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen].length>0&&(this.$parent.request[this.listen].lengthparseInt(d[2]))&&(this.addError(d),a=!1);break;case"between_number":if(d.length<3)throw"One or all between values are not defined in validation rules";void 0!==this.$parent.request[this.listen]&&(parseInt(this.$parent.request[this.listen])parseInt(d[2]))&&(this.addError(d),a=!1);break;case"email":var e=/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;void 0===this.$parent.request[this.listen]||e.test(this.$parent.request[this.listen])||(this.addError(d),a=!1)}}return a},addError:function(a){void 0===this.$parent.response&&this.$parent.$set("response",{}),void 0===this.$parent.response.errors&&this.$parent.$set("response.errors",{}),void 0===this.$parent.response.errors[this.listen]&&this.$parent.$set("response.errors."+this.listen,[]);var b=this.$parent.errors[a[0]];a.length>1&&(b=b.replace(/\%1\%/,a[1])),a.length>2&&(b=b.replace(/\%2\%/,a[2])),this.$parent.response.errors[this.listen].push(b)}}}),results:Vue.extend({props:{model:{type:[Array,Object,String],"default":function(){return[]}},request:{type:Object,"default":function(){return{}}},fetchOnready:{type:[String,Boolean],"default":!1},clearOnFetch:{type:[String,Boolean],"default":!0}},data:function(){return{buffer:[]}},computed:{records:function(){if(!this.$parent.hasMessage&&Array.isArray(this.model))if(this.clearOnFetch)this.$set("buffer",this.model);else for(var a in this.model)void 0!==this.model[a]&&null!==this.model[a]&&this.buffer.push(this.model[a]);return this.buffer},hasRecords:function(){return this.records.length>0}},ready:function(){this.fetchOnready&&this.$parent.submit()}})}})); \ No newline at end of file +"use strict";Vue.component("vform",Vue.extend({props:{action:{type:String,"default":""},method:{type:String,"default":"POST"},headers:{type:Object,"default":function(){}},timeout:{type:[String,Number],"default":void 0},credentials:{type:[String,Boolean],"default":void 0},emulateHttp:{type:[String,Boolean],"default":void 0},emulateJson:{type:[String,Boolean],"default":void 0},errors:{type:Object,"default":function(){return{required:"Required field.",number:"Value must be numeric.",email:"Email value is invalid.",min:"Value must have at least %1% character(s).",min_number:"Value must be at least %1%.",max:"Value must have no more than %1% character(s).",max_number:"Value must be no more than %1%.",between:"Value must have between %1% to %2% characters.",between_number:"Value must be between %1% to %2%.",equals:"Value must be equal to %1%.",required_if:"Required field.",url:"Url value is invalid."}}},id:{type:[String,Number],"default":void 0},key:{type:[String,Number],"default":void 0}},data:function(){return{request:{},isLoading:!1,response:{}}},computed:{hasMessage:function(){return void 0!=this.response.message},hasError:function(){return void 0!=this.response.error&&this.response.error}},methods:{submit:function(){var a=!0;this.$set("response",{});for(var b in this.$children)"function"==typeof this.$children[b].validate&&(a=this.$children[b].validate()&&a);a?(this.$set("isLoading",!0),this.$http(this.getOptions()).then(this.onSubmit,this.onError)):(this.$dispatch("vform_invalid",this.response.errors),this.$broadcast("vform_invalid",this.response.errors))},onSubmit:function(a){return this.$set("response",a.data),this.$dispatch("vform_success"),this.$broadcast("vform_success"),void 0!==this.response.errors&&Object.keys(this.response.errors).length>0&&(this.$dispatch("vform_invalid",this.response.errors),this.$broadcast("vform_invalid",this.response.errors)),void 0!==a.data.redirect?window.location=a.data.redirect:void this.onComplete()},onComplete:function(){this.$set("isLoading",!1),this.$dispatch("vform_complete"),this.$broadcast("vform_complete")},onError:function(a){console.log(a),this.$dispatch("vform_error",a),this.$broadcast("vform_error",a),this.onComplete()},getOptions:function(){var a={url:this.action,method:this.method};switch(void 0!==this.headers&&(a.headers=this.headers),void 0!==this.timeout&&(a.timeout=this.timeout),void 0!==this.credentials&&(a.credentials="boolean"==typeof this.credentials?this.credentials:"true"===this.credentials),void 0!==this.emulateHttp&&(a.emulateHTTP="boolean"==typeof this.emulateHttp?this.emulateHttp:"true"===this.emulateHttp),void 0!==this.emulateJson&&(a.emulateJSON="boolean"==typeof this.emulateJson?this.emulateJson:"true"===this.emulateJson),this.method){case"post":case"POST":case"put":case"PUT":case"patch":case"PATCH":a.body=this.request;break;default:a.params=this.request}return a}},components:{"input-handler":Vue.extend({template:'
  • {{error}}
',props:{listen:{type:String,"default":""},"class":{type:String,"default":""},classError:{type:String,"default":void 0},response:{type:[Object,Array],"default":function(){return{}}},validations:{type:String,"default":""}},computed:{inputErrors:function(){var a=[];return void 0!==this.response.errors&&void 0!==this.response.errors[this.listen]&&(a=this.response.errors[this.listen]),a},hasErrors:function(){return this.inputErrors.length>0},errorCss:function(){var a={};return void 0!==this.classError&&(a[this.classError]=this.hasErrors),a}},methods:{validate:function(){var a=!0,b=this.validations.split("|");for(var c in b){var d=b[c].split(":");switch(d[0]){case"required":void 0!==this.$parent.request[this.listen]&&0!==this.$parent.request[this.listen].length||(this.addError(d),a=!1);break;case"number":void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen].length>0&&isNaN(this.$parent.request[this.listen])&&(this.addError(d),a=!1);break;case"min":if(d.length<2)throw"Minimum value is not defined in validation rules";void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen].length>0&&this.$parent.request[this.listen].length0&&this.$parent.request[this.listen].length>parseInt(d[1])&&(this.addError(d),a=!1);break;case"max_number":if(d.length<2)throw"Minimum value is not defined in validation rules";void 0!==this.$parent.request[this.listen]&&parseInt(this.$parent.request[this.listen])>parseInt(d[1])&&(this.addError(d),a=!1);break;case"between":if(d.length<3)throw"One or all between values are not defined in validation rules";void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen].length>0&&(this.$parent.request[this.listen].lengthparseInt(d[2]))&&(this.addError(d),a=!1);break;case"between_number":if(d.length<3)throw"One or all between values are not defined in validation rules";void 0!==this.$parent.request[this.listen]&&(parseInt(this.$parent.request[this.listen])parseInt(d[2]))&&(this.addError(d),a=!1);break;case"email":var e=/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;void 0===this.$parent.request[this.listen]||e.test(this.$parent.request[this.listen])||(this.addError(d),a=!1);break;case"equals":if(d.length<2)throw"Comparison field is not defined in validation rules";void 0!==this.$parent.request[this.listen]&&this.$parent.request[this.listen]!==this.$parent.request[d[1]]&&(this.addError(d),a=!1);break;case"required_if":if(d.length<2)throw"Comparison field is not defined in validation rules";void 0!==this.$parent.request[d[1]]&&this.$parent.request[d[1]].length>0&&(void 0===this.$parent.request[this.listen]||0===this.$parent.request[this.listen].length)&&(this.addError(d),a=!1);break;case"url":var e=/(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/;void 0===this.$parent.request[this.listen]||e.test(this.$parent.request[this.listen])||(this.addError(d),a=!1)}}return a},addError:function(a){void 0===this.$parent.response&&this.$parent.$set("response",{}),void 0===this.$parent.response.errors&&this.$parent.$set("response.errors",{}),void 0===this.$parent.response.errors[this.listen]&&this.$parent.$set("response.errors."+this.listen,[]);var b=this.$parent.errors[a[0]];a.length>1&&(b=b.replace(/\%1\%/,a[1])),a.length>2&&(b=b.replace(/\%2\%/,a[2])),this.$parent.response.errors[this.listen].push(b)}}}),results:Vue.extend({props:{model:{type:[Array,Object,String],"default":function(){return[]}},request:{type:Object,"default":function(){return{}}},fetchOnready:{type:[String,Boolean],"default":!1},clearOnFetch:{type:[String,Boolean],"default":!0}},data:function(){return{buffer:[]}},computed:{records:function(){if(!this.$parent.hasMessage&&Array.isArray(this.model))if(this.clearOnFetch)this.$set("buffer",this.model);else for(var a in this.model)void 0!==this.model[a]&&null!==this.model[a]&&this.buffer.push(this.model[a]);return this.buffer},hasRecords:function(){return this.records.length>0}},ready:function(){this.fetchOnready&&this.$parent.submit()}})}})); \ No newline at end of file diff --git a/package.json b/package.json index 48e5bd2..33690fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-form", - "version": "1.0.5", + "version": "1.0.7", "description": "Form component for Vue JS.", "main": "dist/vue.social-share.js", "repository": { diff --git a/src/vue.form.js b/src/vue.form.js index e9d586a..532a298 100644 --- a/src/vue.form.js +++ b/src/vue.form.js @@ -6,7 +6,7 @@ * @author Alejandro Mostajo * @copyright 10Quality * @license MIT - * @version 1.0.5 + * @version 1.0.7 */ Vue.component('vform', Vue.extend({ props: @@ -84,6 +84,7 @@ Vue.component('vform', Vue.extend({ /** * List of default errors. * @since 1.0.2 + * @since 1.0.7 Added equal,required_if,url * @var object */ errors: @@ -100,6 +101,9 @@ Vue.component('vform', Vue.extend({ max_number: 'Value must be no more than %1%.', between: 'Value must have between %1% to %2% characters.', between_number: 'Value must be between %1% to %2%.', + equals: 'Value must be equal to %1%.', + required_if: 'Required field.', + url: 'Url value is invalid.', }; }, }, @@ -396,6 +400,7 @@ Vue.component('vform', Vue.extend({ /** * Validates input. * @since 1.0.2 + * @since 1.0.7 Added equal,required_if,url * * @return bool */ @@ -499,6 +504,38 @@ Vue.component('vform', Vue.extend({ success = false; } break; + case 'equals': + if (options.length < 2) + throw 'Comparison field is not defined in validation rules'; + if (this.$parent.request[this.listen] !== undefined + && this.$parent.request[this.listen] !== this.$parent.request[options[1]] + ) { + this.addError(options); + success = false; + } + break; + case 'required_if': + if (options.length < 2) + throw 'Comparison field is not defined in validation rules'; + if (this.$parent.request[options[1]] !== undefined + && this.$parent.request[options[1]].length > 0 + && (this.$parent.request[this.listen] === undefined + || this.$parent.request[this.listen].length === 0 + ) + ) { + this.addError(options); + success = false; + } + break; + case 'url': + var regex = /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/; + if (this.$parent.request[this.listen] !== undefined + && !regex.test(this.$parent.request[this.listen]) + ) { + this.addError(options); + success = false; + } + break; } } return success; diff --git a/tests/test2.html b/tests/test2.html new file mode 100644 index 0000000..6d23e29 --- /dev/null +++ b/tests/test2.html @@ -0,0 +1,90 @@ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + Loading... +
+
+
+ + + + + + + \ No newline at end of file