diff --git a/dist/simple-react-validator.js b/dist/simple-react-validator.js index a3a731a..1d93bb0 100644 --- a/dist/simple-react-validator.js +++ b/dist/simple-react-validator.js @@ -22,6 +22,10 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } +function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } + +function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } @@ -58,18 +62,52 @@ function () { _defineProperty(this, "helpers", { parent: this, - passes: function passes(rule, value, params, rules) { - if (!rules.hasOwnProperty(rule)) { - console.error("Rule Not Found: There is no rule with the name ".concat(rule, ".")); - return true; - } + passes: function () { + var _passes = _asyncToGenerator( + /*#__PURE__*/ + regeneratorRuntime.mark(function _callee(rule, value, params, rules) { + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + if (rules.hasOwnProperty(rule)) { + _context.next = 3; + break; + } + + console.error("Rule Not Found: There is no rule with the name ".concat(rule, ".")); + return _context.abrupt("return", true); + + case 3: + if (!(!this.isRequired(rule, rules) && this.isBlank(value))) { + _context.next = 5; + break; + } + + return _context.abrupt("return", true); + + case 5: + _context.next = 7; + return rules[rule].rule(value, params, this.parent); + + case 7: + _context.t0 = _context.sent; + return _context.abrupt("return", _context.t0 !== false); + + case 9: + case "end": + return _context.stop(); + } + } + }, _callee, this); + })); - if (!this.isRequired(rule, rules) && this.isBlank(value)) { - return true; + function passes(_x, _x2, _x3, _x4) { + return _passes.apply(this, arguments); } - return rules[rule].rule(value, params, this.parent) !== false; - }, + return passes; + }(), isRequired: function isRequired(rule, rules) { return rules[rule].hasOwnProperty('required') && rules[rule].required; }, @@ -432,6 +470,7 @@ function () { }, { key: "showMessages", value: function showMessages() { + console.log(this.errorMessages); this.messagesShown = true; this.helpers.forceUpdateIfNeeded(); } @@ -484,60 +523,78 @@ function () { } }, { key: "message", - value: function message(field, inputValue, validations) { - var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; - this.errorMessages[field] = null; - this.fields[field] = true; + value: function message(field) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - if (!Array.isArray(validations)) { - validations = validations.split('|'); + if (this.messagesShown || this.visibleFields.includes(field)) { + var message = this.errorMessages[field]; + console.log('message ', message); + return this.helpers.element(message, options); } - - var rules = options.validators ? _objectSpread({}, this.rules, options.validators) : this.rules; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = validations[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var validation = _step.value; - - var _this$helpers$normali = this.helpers.normalizeValues(inputValue, validation), - _this$helpers$normali2 = _slicedToArray(_this$helpers$normali, 3), - value = _this$helpers$normali2[0], - rule = _this$helpers$normali2[1], - params = _this$helpers$normali2[2]; - - if (!this.helpers.passes(rule, value, params, rules)) { - this.fields[field] = false; - var message = this.helpers.message(rule, field, options, rules); - - if (params.length > 0 && rules[rule].hasOwnProperty('messageReplace')) { - message = rules[rule].messageReplace(message, params); - } - - this.errorMessages[field] = message; - - if (this.messagesShown || this.visibleFields.includes(field)) { - return this.helpers.element(message, options); + } + }, { + key: "validate", + value: function () { + var _validate = _asyncToGenerator( + /*#__PURE__*/ + regeneratorRuntime.mark(function _callee2(field, inputValue, validations) { + var _this2 = this; + + var options, + rules, + _args2 = arguments; + return regeneratorRuntime.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + options = _args2.length > 3 && _args2[3] !== undefined ? _args2[3] : {}; + + if (!Array.isArray(validations)) { + validations = validations.split('|'); + } + + rules = options.validators ? _objectSpread({}, this.rules, options.validators) : this.rules; + return _context2.abrupt("return", Promise.all(validations.map(function (validation) { + var _this2$helpers$normal = _this2.helpers.normalizeValues(inputValue, validation), + _this2$helpers$normal2 = _slicedToArray(_this2$helpers$normal, 3), + value = _this2$helpers$normal2[0], + rule = _this2$helpers$normal2[1], + params = _this2$helpers$normal2[2]; + + return _this2.helpers.passes(rule, value, params, rules).then(function (res) { + _this2.errorMessages[field] = null; + _this2.fields[field] = true; + + if (!res) { + _this2.fields[field] = false; + + var message = _this2.helpers.message(rule, field, options, rules); + + if (params.length > 0 && rules[rule].hasOwnProperty('messageReplace')) { + message = rules[rule].messageReplace(message, params); + } + + _this2.errorMessages[field] = message; + } + + return res; + }); + }))); + + case 4: + case "end": + return _context2.stop(); } } - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator["return"] != null) { - _iterator["return"](); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } + }, _callee2, this); + })); + + function validate(_x5, _x6, _x7) { + return _validate.apply(this, arguments); } - } + + return validate; + }() }]); return SimpleReactValidator; diff --git a/dist/simple-react-validator.min.js b/dist/simple-react-validator.min.js index 0ef1779..0bc3ea2 100644 --- a/dist/simple-react-validator.min.js +++ b/dist/simple-react-validator.min.js @@ -1,2 +1,2 @@ // Simple React Validator v1.1.0 | Created By Dockwa | MIT License | 2017 - Present -!function(e,t){"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?module.exports=t(require("react")):e.SimpleReactValidator=t(e.React)}(this,function(s){"use strict";function g(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=[],n=!0,s=!1,a=void 0;try{for(var i,u=e[Symbol.iterator]();!(n=(i=u.next()).done)&&(r.push(i.value),!t||r.length!==t);n=!0);}catch(e){s=!0,a=e}finally{try{n||null==u.return||u.return()}finally{if(s)throw a}}return r}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function b(t){for(var e=1;e=parseFloat(t[0])&&r.helpers.size(e,t[2])<=parseFloat(t[1])},messageReplace:function(e,t){return e.replace(":min",t[0]).replace(":max",t[1]).replace(":type",r.helpers.sizeText(t[2]))}},boolean:{message:"The :attribute must be a boolean.",rule:function(e){return!1===e||!0===e}},card_exp:{message:"The :attribute must be a valid expiration date.",rule:function(e){return r.helpers.testRegex(e,/^(([0]?[1-9]{1})|([1]{1}[0-2]{1}))\s?\/\s?(\d{2}|\d{4})$/)}},card_num:{message:"The :attribute must be a valid credit card number.",rule:function(e){return r.helpers.testRegex(e,/^\d{4}\s?\d{4,6}\s?\d{4,5}\s?\d{0,8}$/)}},currency:{message:"The :attribute must be a valid currency.",rule:function(e){return r.helpers.testRegex(e,/^\$?(\d{1,3})(\,?\d{3})*\.?\d{0,2}$/)}},date:{message:"The :attribute must be a date.",rule:function(e){return r.helpers.momentInstalled()&&moment.isMoment(e)}},date_equals:{message:"The :attribute must be on :date.",rule:function(e,t){return r.helpers.momentInstalled()&&moment.isMoment(e)&&e.isSame(t[0],"day")},messageReplace:function(e,t){return e.replace(":date",t[0].format("MM/DD/YYYY"))}},email:{message:"The :attribute must be a valid email address.",rule:function(e){return r.helpers.testRegex(e,/^[A-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)}},in:{message:"The selected :attribute must be :values.",rule:function(e,t){return-1=parseFloat(t[0])},messageReplace:function(e,t){return e.replace(":min",t[0]).replace(":type",r.helpers.sizeText(t[1]))}},not_in:{message:"The selected :attribute must not be :values.",rule:function(e,t){return-1===t.indexOf(e)},messageReplace:function(e,t){return e.replace(":values",r.helpers.toSentence(t))}},not_regex:{message:"The :attribute must not match the required pattern.",rule:function(e,t){return!r.helpers.testRegex(e,"string"==typeof t[0]||t[0]instanceof String?new RegExp(t[0]):t[0])}},numeric:{message:"The :attribute must be a number.",rule:function(e){return r.helpers.numeric(e)}},phone:{message:"The :attribute must be a valid phone number.",rule:function(e){return r.helpers.testRegex(e,/^(\+?\d{0,4})?\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{4}\)?)?$/)}},regex:{message:"The :attribute must match the required pattern.",rule:function(e,t){return r.helpers.testRegex(e,"string"==typeof t[0]||t[0]instanceof String?new RegExp(t[0]):t[0])}},required:{message:"The :attribute field is required.",rule:function(e){return!r.helpers.isBlank(e)},required:!0},size:{message:"The :attribute must be :size:type.",rule:function(e,t){return r.helpers.size(e,t[1])==parseFloat(t[0])},messageReplace:function(e,t){return e.replace(":size",t[0]).replace(":type",r.helpers.sizeText(t[1]))}},string:{message:"The :attribute must be a string.",rule:function(e){return a(e)===a("string")}},typeof:{message:"The :attribute is not the correct type of :type.",rule:function(e,t){return a(e)===a(t[0])},messageReplace:function(e,t){return e.replace(":type",a(t[0]))}},url:{message:"The :attribute must be a url.",rule:function(e){return r.helpers.testRegex(e,/^(https?|ftp):\/\/(-\.)?([^\s/?\.#-]+\.?)+(\/[^\s]*)?$/i)}}},e.validators||{}),this.messages=e.messages||{},this.className=e.className,this.autoForceUpdate=e.autoForceUpdate||!1,!1===e.element?this.element=function(e){return e}:e.hasOwnProperty("element")?this.element=e.element:"object"===("undefined"==typeof navigator?"undefined":a(navigator))&&"ReactNative"===navigator.product?this.element=function(e){return e}:this.element=function(e,t){return s.createElement("div",{className:t||r.className||"srv-validation-message"},e)}}var e,r,n;return e=t,(r=[{key:"getErrorMessages",value:function(){return this.errorMessages}},{key:"showMessages",value:function(){this.messagesShown=!0,this.helpers.forceUpdateIfNeeded()}},{key:"hideMessages",value:function(){this.messagesShown=!1,this.helpers.forceUpdateIfNeeded()}},{key:"allValid",value:function(){for(var e in this.fields)if(!1===this.fieldValid(e))return!1;return!0}},{key:"fieldValid",value:function(e){return this.fields.hasOwnProperty(e)&&!0===this.fields[e]}},{key:"purgeFields",value:function(){this.fields={},this.errorMessages={}}},{key:"messageWhenPresent",value:function(e){var t=1=parseFloat(t[0])&&r.helpers.size(e,t[2])<=parseFloat(t[1])},messageReplace:function(e,t){return e.replace(":min",t[0]).replace(":max",t[1]).replace(":type",r.helpers.sizeText(t[2]))}},boolean:{message:"The :attribute must be a boolean.",rule:function(e){return!1===e||!0===e}},card_exp:{message:"The :attribute must be a valid expiration date.",rule:function(e){return r.helpers.testRegex(e,/^(([0]?[1-9]{1})|([1]{1}[0-2]{1}))\s?\/\s?(\d{2}|\d{4})$/)}},card_num:{message:"The :attribute must be a valid credit card number.",rule:function(e){return r.helpers.testRegex(e,/^\d{4}\s?\d{4,6}\s?\d{4,5}\s?\d{0,8}$/)}},currency:{message:"The :attribute must be a valid currency.",rule:function(e){return r.helpers.testRegex(e,/^\$?(\d{1,3})(\,?\d{3})*\.?\d{0,2}$/)}},date:{message:"The :attribute must be a date.",rule:function(e){return r.helpers.momentInstalled()&&moment.isMoment(e)}},date_equals:{message:"The :attribute must be on :date.",rule:function(e,t){return r.helpers.momentInstalled()&&moment.isMoment(e)&&e.isSame(t[0],"day")},messageReplace:function(e,t){return e.replace(":date",t[0].format("MM/DD/YYYY"))}},email:{message:"The :attribute must be a valid email address.",rule:function(e){return r.helpers.testRegex(e,/^[A-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)}},in:{message:"The selected :attribute must be :values.",rule:function(e,t){return-1=parseFloat(t[0])},messageReplace:function(e,t){return e.replace(":min",t[0]).replace(":type",r.helpers.sizeText(t[1]))}},not_in:{message:"The selected :attribute must not be :values.",rule:function(e,t){return-1===t.indexOf(e)},messageReplace:function(e,t){return e.replace(":values",r.helpers.toSentence(t))}},not_regex:{message:"The :attribute must not match the required pattern.",rule:function(e,t){return!r.helpers.testRegex(e,"string"==typeof t[0]||t[0]instanceof String?new RegExp(t[0]):t[0])}},numeric:{message:"The :attribute must be a number.",rule:function(e){return r.helpers.numeric(e)}},phone:{message:"The :attribute must be a valid phone number.",rule:function(e){return r.helpers.testRegex(e,/^(\+?\d{0,4})?\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{4}\)?)?$/)}},regex:{message:"The :attribute must match the required pattern.",rule:function(e,t){return r.helpers.testRegex(e,"string"==typeof t[0]||t[0]instanceof String?new RegExp(t[0]):t[0])}},required:{message:"The :attribute field is required.",rule:function(e){return!r.helpers.isBlank(e)},required:!0},size:{message:"The :attribute must be :size:type.",rule:function(e,t){return r.helpers.size(e,t[1])==parseFloat(t[0])},messageReplace:function(e,t){return e.replace(":size",t[0]).replace(":type",r.helpers.sizeText(t[1]))}},string:{message:"The :attribute must be a string.",rule:function(e){return i(e)===i("string")}},typeof:{message:"The :attribute is not the correct type of :type.",rule:function(e,t){return i(e)===i(t[0])},messageReplace:function(e,t){return e.replace(":type",i(t[0]))}},url:{message:"The :attribute must be a url.",rule:function(e){return r.helpers.testRegex(e,/^(https?|ftp):\/\/(-\.)?([^\s/?\.#-]+\.?)+(\/[^\s]*)?$/i)}}},e.validators||{}),this.messages=e.messages||{},this.className=e.className,this.autoForceUpdate=e.autoForceUpdate||!1,!1===e.element?this.element=function(e){return e}:e.hasOwnProperty("element")?this.element=e.element:"object"===("undefined"==typeof navigator?"undefined":i(navigator))&&"ReactNative"===navigator.product?this.element=function(e){return e}:this.element=function(e,t){return a.createElement("div",{className:t||r.className||"srv-validation-message"},e)}}var e,r,n,s;return e=t,(r=[{key:"getErrorMessages",value:function(){return this.errorMessages}},{key:"showMessages",value:function(){console.log(this.errorMessages),this.messagesShown=!0,this.helpers.forceUpdateIfNeeded()}},{key:"hideMessages",value:function(){this.messagesShown=!1,this.helpers.forceUpdateIfNeeded()}},{key:"allValid",value:function(){for(var e in this.fields)if(!1===this.fieldValid(e))return!1;return!0}},{key:"fieldValid",value:function(e){return this.fields.hasOwnProperty(e)&&!0===this.fields[e]}},{key:"purgeFields",value:function(){this.fields={},this.errorMessages={}}},{key:"messageWhenPresent",value:function(e){var t=1 val === true, required: true}, - after : {message: 'The :attribute must be after :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isAfter(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY'))}, - after_or_equal : {message: 'The :attribute must be after or on :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isSameOrAfter(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY'))}, - alpha : {message: 'The :attribute may only contain letters.', rule: val => this.helpers.testRegex(val,/^[A-Z]*$/i)}, - alpha_space : {message: 'The :attribute may only contain letters and spaces.', rule: val => this.helpers.testRegex(val,/^[A-Z\s]*$/i)}, - alpha_num : {message: 'The :attribute may only contain letters and numbers.', rule: val => this.helpers.testRegex(val,/^[A-Z0-9]*$/i)}, - alpha_num_space : {message: 'The :attribute may only contain letters, numbers, and spaces.', rule: val => this.helpers.testRegex(val,/^[A-Z0-9\s]*$/i)}, - alpha_num_dash : {message: 'The :attribute may only contain letters, numbers, and dashes.', rule: val => this.helpers.testRegex(val,/^[A-Z0-9_-]*$/i)}, - alpha_num_dash_space : {message: 'The :attribute may only contain letters, numbers, dashes, and spaces.', rule: val => this.helpers.testRegex(val,/^[A-Z0-9_-\s]*$/i)}, - array : {message: 'The :attribute must be an array.', rule: val => Array.isArray(val)}, - before : {message: 'The :attribute must be before :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isBefore(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY'))}, - before_or_equal : {message: 'The :attribute must be before or on :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isSameOrBefore(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY'))}, - between : {message: 'The :attribute must be between :min and :max:type.', rule: (val, params) => this.helpers.size(val, params[2]) >= parseFloat(params[0]) && this.helpers.size(val, params[2]) <= parseFloat(params[1]), messageReplace: (message, params) => message.replace(':min', params[0]).replace(':max', params[1]).replace(':type', this.helpers.sizeText(params[2]))}, - boolean : {message: 'The :attribute must be a boolean.', rule: val => val === false || val === true}, - card_exp : {message: 'The :attribute must be a valid expiration date.', rule: val => this.helpers.testRegex(val,/^(([0]?[1-9]{1})|([1]{1}[0-2]{1}))\s?\/\s?(\d{2}|\d{4})$/)}, - card_num : {message: 'The :attribute must be a valid credit card number.', rule: val => this.helpers.testRegex(val,/^\d{4}\s?\d{4,6}\s?\d{4,5}\s?\d{0,8}$/)}, - currency : {message: 'The :attribute must be a valid currency.', rule: val => this.helpers.testRegex(val,/^\$?(\d{1,3})(\,?\d{3})*\.?\d{0,2}$/)}, - date : {message: 'The :attribute must be a date.', rule: val => this.helpers.momentInstalled() && moment.isMoment(val)}, - date_equals : {message: 'The :attribute must be on :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isSame(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY'))}, - email : {message: 'The :attribute must be a valid email address.', rule: val => this.helpers.testRegex(val,/^[A-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)}, - in : {message: 'The selected :attribute must be :values.', rule: (val, params) => params.indexOf(val) > -1, messageReplace: (message, params) => message.replace(':values', this.helpers.toSentence(params))}, - integer : {message: 'The :attribute must be an integer.', rule: val => this.helpers.testRegex(val,/^\d*$/)}, - max : {message: 'The :attribute may not be greater than :max:type.', rule: (val, params) => this.helpers.size(val, params[1]) <= parseFloat(params[0]), messageReplace: (message, params) => message.replace(':max', params[0]).replace(':type', this.helpers.sizeText(params[1]))}, - min : {message: 'The :attribute must be at least :min:type.', rule: (val, params) => this.helpers.size(val, params[1]) >= parseFloat(params[0]), messageReplace: (message, params) => message.replace(':min', params[0]).replace(':type', this.helpers.sizeText(params[1]))}, - not_in : {message: 'The selected :attribute must not be :values.', rule: (val, params) => params.indexOf(val) === -1, messageReplace: (message, params) => message.replace(':values', this.helpers.toSentence(params))}, - not_regex : {message: 'The :attribute must not match the required pattern.', rule: (val, params) => !this.helpers.testRegex(val, typeof params[0] === 'string' || params[0] instanceof String ? new RegExp(params[0]) : params[0])}, - numeric : {message: 'The :attribute must be a number.', rule: val => this.helpers.numeric(val)}, - phone : {message: 'The :attribute must be a valid phone number.', rule: val => this.helpers.testRegex(val,/^(\+?\d{0,4})?\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{4}\)?)?$/)}, - regex : {message: 'The :attribute must match the required pattern.', rule: (val, params) => this.helpers.testRegex(val, typeof params[0] === 'string' || params[0] instanceof String ? new RegExp(params[0]) : params[0])}, - required : {message: 'The :attribute field is required.', rule: val => !this.helpers.isBlank(val), required: true }, - size : {message: 'The :attribute must be :size:type.', rule: (val, params) => this.helpers.size(val, params[1]) == parseFloat(params[0]), messageReplace: (message, params) => message.replace(':size', params[0]).replace(':type', this.helpers.sizeText(params[1]))}, - string : {message: 'The :attribute must be a string.', rule: val => typeof(val) === typeof('string')}, - typeof : {message: 'The :attribute is not the correct type of :type.', rule: (val, params) => typeof(val) === typeof(params[0]), messageReplace: (message, params) => message.replace(':type', typeof(params[0]))}, - url : {message: 'The :attribute must be a url.', rule: val => this.helpers.testRegex(val,/^(https?|ftp):\/\/(-\.)?([^\s/?\.#-]+\.?)+(\/[^\s]*)?$/i)}, + accepted: { message: 'The :attribute must be accepted.', rule: val => val === true, required: true }, + after: { message: 'The :attribute must be after :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isAfter(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY')) }, + after_or_equal: { message: 'The :attribute must be after or on :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isSameOrAfter(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY')) }, + alpha: { message: 'The :attribute may only contain letters.', rule: val => this.helpers.testRegex(val, /^[A-Z]*$/i) }, + alpha_space: { message: 'The :attribute may only contain letters and spaces.', rule: val => this.helpers.testRegex(val, /^[A-Z\s]*$/i) }, + alpha_num: { message: 'The :attribute may only contain letters and numbers.', rule: val => this.helpers.testRegex(val, /^[A-Z0-9]*$/i) }, + alpha_num_space: { message: 'The :attribute may only contain letters, numbers, and spaces.', rule: val => this.helpers.testRegex(val, /^[A-Z0-9\s]*$/i) }, + alpha_num_dash: { message: 'The :attribute may only contain letters, numbers, and dashes.', rule: val => this.helpers.testRegex(val, /^[A-Z0-9_-]*$/i) }, + alpha_num_dash_space: { message: 'The :attribute may only contain letters, numbers, dashes, and spaces.', rule: val => this.helpers.testRegex(val, /^[A-Z0-9_-\s]*$/i) }, + array: { message: 'The :attribute must be an array.', rule: val => Array.isArray(val) }, + before: { message: 'The :attribute must be before :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isBefore(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY')) }, + before_or_equal: { message: 'The :attribute must be before or on :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isSameOrBefore(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY')) }, + between: { message: 'The :attribute must be between :min and :max:type.', rule: (val, params) => this.helpers.size(val, params[2]) >= parseFloat(params[0]) && this.helpers.size(val, params[2]) <= parseFloat(params[1]), messageReplace: (message, params) => message.replace(':min', params[0]).replace(':max', params[1]).replace(':type', this.helpers.sizeText(params[2])) }, + boolean: { message: 'The :attribute must be a boolean.', rule: val => val === false || val === true }, + card_exp: { message: 'The :attribute must be a valid expiration date.', rule: val => this.helpers.testRegex(val, /^(([0]?[1-9]{1})|([1]{1}[0-2]{1}))\s?\/\s?(\d{2}|\d{4})$/) }, + card_num: { message: 'The :attribute must be a valid credit card number.', rule: val => this.helpers.testRegex(val, /^\d{4}\s?\d{4,6}\s?\d{4,5}\s?\d{0,8}$/) }, + currency: { message: 'The :attribute must be a valid currency.', rule: val => this.helpers.testRegex(val, /^\$?(\d{1,3})(\,?\d{3})*\.?\d{0,2}$/) }, + date: { message: 'The :attribute must be a date.', rule: val => this.helpers.momentInstalled() && moment.isMoment(val) }, + date_equals: { message: 'The :attribute must be on :date.', rule: (val, params) => this.helpers.momentInstalled() && moment.isMoment(val) && val.isSame(params[0], 'day'), messageReplace: (message, params) => message.replace(':date', params[0].format('MM/DD/YYYY')) }, + email: { message: 'The :attribute must be a valid email address.', rule: val => this.helpers.testRegex(val, /^[A-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i) }, + in: { message: 'The selected :attribute must be :values.', rule: (val, params) => params.indexOf(val) > -1, messageReplace: (message, params) => message.replace(':values', this.helpers.toSentence(params)) }, + integer: { message: 'The :attribute must be an integer.', rule: val => this.helpers.testRegex(val, /^\d*$/) }, + max: { message: 'The :attribute may not be greater than :max:type.', rule: (val, params) => this.helpers.size(val, params[1]) <= parseFloat(params[0]), messageReplace: (message, params) => message.replace(':max', params[0]).replace(':type', this.helpers.sizeText(params[1])) }, + min: { message: 'The :attribute must be at least :min:type.', rule: (val, params) => this.helpers.size(val, params[1]) >= parseFloat(params[0]), messageReplace: (message, params) => message.replace(':min', params[0]).replace(':type', this.helpers.sizeText(params[1])) }, + not_in: { message: 'The selected :attribute must not be :values.', rule: (val, params) => params.indexOf(val) === -1, messageReplace: (message, params) => message.replace(':values', this.helpers.toSentence(params)) }, + not_regex: { message: 'The :attribute must not match the required pattern.', rule: (val, params) => !this.helpers.testRegex(val, typeof params[0] === 'string' || params[0] instanceof String ? new RegExp(params[0]) : params[0]) }, + numeric: { message: 'The :attribute must be a number.', rule: val => this.helpers.numeric(val) }, + phone: { message: 'The :attribute must be a valid phone number.', rule: val => this.helpers.testRegex(val, /^(\+?\d{0,4})?\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{4}\)?)?$/) }, + regex: { message: 'The :attribute must match the required pattern.', rule: (val, params) => this.helpers.testRegex(val, typeof params[0] === 'string' || params[0] instanceof String ? new RegExp(params[0]) : params[0]) }, + required: { message: 'The :attribute field is required.', rule: val => !this.helpers.isBlank(val), required: true }, + size: { message: 'The :attribute must be :size:type.', rule: (val, params) => this.helpers.size(val, params[1]) == parseFloat(params[0]), messageReplace: (message, params) => message.replace(':size', params[0]).replace(':type', this.helpers.sizeText(params[1])) }, + string: { message: 'The :attribute must be a string.', rule: val => typeof (val) === typeof ('string') }, + typeof: { message: 'The :attribute is not the correct type of :type.', rule: (val, params) => typeof (val) === typeof (params[0]), messageReplace: (message, params) => message.replace(':type', typeof (params[0])) }, + url: { message: 'The :attribute must be a url.', rule: val => this.helpers.testRegex(val, /^(https?|ftp):\/\/(-\.)?([^\s/?\.#-]+\.?)+(\/[^\s]*)?$/i) }, ...(options.validators || {}), }; @@ -55,7 +55,7 @@ class SimpleReactValidator { } else if (typeof navigator === 'object' && navigator.product === 'ReactNative') { this.element = message => message; } else { - this.element = (message, className) => React.createElement('div', {className: (className || this.className || 'srv-validation-message')}, message); + this.element = (message, className) => React.createElement('div', { className: (className || this.className || 'srv-validation-message') }, message); } } @@ -64,6 +64,7 @@ class SimpleReactValidator { } showMessages() { + console.log(this.errorMessages) this.messagesShown = true; this.helpers.forceUpdateIfNeeded(); } @@ -117,35 +118,44 @@ class SimpleReactValidator { } } - message(field, inputValue, validations, options = {}) { - this.errorMessages[field] = null; - this.fields[field] = true; + message(field, options = {}) { + if (this.messagesShown || this.visibleFields.includes(field)) { + let message = this.errorMessages[field] + console.log('message ', message) + return this.helpers.element(message, options); + } + } + + async validate(field, inputValue, validations, options = {}) { if (!Array.isArray(validations)) { validations = validations.split('|'); } - var rules = options.validators ? {...this.rules, ...options.validators} : this.rules; - for (let validation of validations) { + var rules = options.validators ? { ...this.rules, ...options.validators } : this.rules; + return Promise.all(validations.map(validation => { let [value, rule, params] = this.helpers.normalizeValues(inputValue, validation); - if (!this.helpers.passes(rule, value, params, rules)) { - this.fields[field] = false; - let message = this.helpers.message(rule, field, options, rules); - - if (params.length > 0 && rules[rule].hasOwnProperty('messageReplace')) { - message = rules[rule].messageReplace(message, params); - } - - this.errorMessages[field] = message; - if (this.messagesShown || this.visibleFields.includes(field)) { - return this.helpers.element(message, options); - } - } - } + return this.helpers.passes(rule, value, params, rules) + .then(res => { + this.errorMessages[field] = null; + this.fields[field] = true; + if (!res) { + this.fields[field] = false; + let message = this.helpers.message(rule, field, options, rules); + + if (params.length > 0 && rules[rule].hasOwnProperty('messageReplace')) { + message = rules[rule].messageReplace(message, params); + } + + this.errorMessages[field] = message; + } + return res + }) + })) } helpers = { parent: this, - passes(rule, value, params, rules) { + async passes(rule, value, params, rules) { if (!rules.hasOwnProperty(rule)) { console.error(`Rule Not Found: There is no rule with the name ${rule}.`); return true; @@ -153,7 +163,7 @@ class SimpleReactValidator { if (!this.isRequired(rule, rules) && this.isBlank(value)) { return true; } - return rules[rule].rule(value, params, this.parent) !== false; + return (await rules[rule].rule(value, params, this.parent)) !== false; }, isRequired(rule, rules) { @@ -161,7 +171,7 @@ class SimpleReactValidator { }, isBlank(value) { - return typeof(value) === 'undefined' || value === null || value === ''; + return typeof (value) === 'undefined' || value === null || value === ''; }, normalizeValues(value, validation) { @@ -192,8 +202,8 @@ class SimpleReactValidator { toSentence(arr) { return arr.slice(0, -2).join(', ') + - (arr.slice(0, -2).length ? ', ' : '') + - arr.slice(-2).join(arr.length > 2 ? ', or ' : ' or '); + (arr.slice(0, -2).length ? ', ' : '') + + arr.slice(-2).join(arr.length > 2 ? ', or ' : ' or '); }, testRegex(value, regex) { @@ -214,7 +224,7 @@ class SimpleReactValidator { humanizeFieldName(field) { // supports snake_case or camelCase - return field.replace( /([A-Z])/g, ' $1' ).replace(/_/g, ' ').toLowerCase(); + return field.replace(/([A-Z])/g, ' $1').replace(/_/g, ' ').toLowerCase(); }, element(message, options) { @@ -223,7 +233,7 @@ class SimpleReactValidator { }, numeric(val) { - return this.testRegex(val,/^(\d+.?\d*)?$/); + return this.testRegex(val, /^(\d+.?\d*)?$/); }, momentInstalled() {