diff --git a/README.md b/README.md
index 82e5381..d3df254 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,23 @@ class MyRegistrationForm extends React.Component {
isEmail: 'Email is invalid'
}}
/>
-
+
);
{
+ var React = require('react');
+ var TestUtils = require('react-addons-test-utils');
+ beforeEach(function() {
+ });
+ it('Validates a number with minimum.', () => {
+ // Render into document
+ var submittedObject = null;
+ var validSubmit = function(event){
+ submittedObject = event;
+ };
+
+ let item = TestUtils.renderIntoDocument(
+ );
+
+ let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1];
+ input.value='not a number';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject).toBe(null);
+
+ input.value='9';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject).toBe(null);
+
+ input.value='19';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject.number).toBe('19');
+
+
+ });
+
+ it('Validates an empty field.', () => {
+ // Render into document
+ var submittedObject = null;
+ var validSubmit = function(event){
+ submittedObject = event;
+ };
+
+ let item = TestUtils.renderIntoDocument(
+ );
+
+ let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1];
+ input.value='aaaa';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject).toBe(null);
+ input.value='';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject.email).toBe('');
+ });
+
+ it('Validates a number.', () => {
+ // Render into document
+ var submittedObject = null;
+ var validSubmit = function(event){
+ submittedObject = event;
+ };
+
+ let item = TestUtils.renderIntoDocument(
+ );
+
+ let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1];
+ input.value='not a number';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject).toBe(null);
+
+ input.value='23';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject.number).toBe('23');
+ });
+
+ it('Validates an email.', () => {
+ // Render into document
+ var submittedObject = null;
+ var validSubmit = function(event){
+ submittedObject = event;
+ };
+
+ let item = TestUtils.renderIntoDocument(
+ );
+
+ let input = TestUtils.scryRenderedDOMComponentsWithClass(item, 'testInput')[1];
+ input.value='notavlidaemailaddress';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ // test for error messages next to the item
+ expect(submittedObject).toBe(null);
+
+ input.value='test@nowhere.com';
+ TestUtils.Simulate.change(input);
+ TestUtils.Simulate.submit(item.refs.form);
+ console.log(submittedObject);
+ expect(submittedObject.email).toBe('test@nowhere.com');
+ });
+
+});
diff --git a/package.json b/package.json
index e31f51d..e535292 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,7 @@
"babel-runtime": "^5.1.10",
"classnames": "^2.0.0",
"react-bootstrap": ">=0.23.0",
- "validator": "^3.41.3",
+ "validator": "^5.2.0",
"react-addons-create-fragment": "^0.14.7"
}
}
diff --git a/src/Form.js b/src/Form.js
index d8b82dc..7625daa 100644
--- a/src/Form.js
+++ b/src/Form.js
@@ -38,7 +38,10 @@ export default class Form extends InputContainer {
if (typeof input.props.validate === 'string') {
this._validators[input.props.name] = this._compileValidationRules(input, input.props.validate);
+ } else if(input.props.validate){
+ this._validators[input.props.name] = this._compileValidationRulesSpecial(input, input.props.validate);
}
+
}
unregisterInput(input) {
@@ -194,13 +197,15 @@ export default class Form extends InputContainer {
result = validate(value, context);
} else if (typeof validate === 'string') {
result = this._validators[iptName](value);
+ } else if(typeof validate === 'object'){
+ result = this._validators[iptName](value);
} else {
result = true;
}
if (typeof this.props.validateOne === 'function') {
result = this.props.validateOne(iptName, value, context, result);
- }
+ }
// if result is !== true, it is considered an error
// it can be either bool or string error
if (result !== true) {
@@ -246,9 +251,65 @@ export default class Form extends InputContainer {
errors: errors
};
}
+ _compileValidationRulesSpecial(input, ruleProp) {
+
+ // Note: need to test against negation as well..
+ let rules = ruleProp.map(rule => {
+ /*
+ {
+ "name" :"isInt",
+ "params": { "min": 10, "max": 99 },
+ "condition": "and",
+ "inverse": false
+ }
+ */
+ let params = [];
+
+ if(rule.params){
+ params = rule.params;
+ }
+
+ let inverse = rule.inverse;
+ return { "name":rule.name, "inverse":rule.inverse, params, "condition":rule.condition };
+ });
+ let validator = (input.props && input.props.type) === 'file' ? FileValidator : Validator;
+
+ return val => {
+ let result = true;
+ let previousResult = true;
+ rules.forEach(rule => {
+ if (typeof validator[rule.name] !== 'function') {
+ throw new Error('Invalid input validation rule "' + rule.name + '"');
+ }
+ let ruleResult = validator[rule.name](val, rule.params);
+
+ if (rule.inverse) {
+ ruleResult = !ruleResult;
+ }
+ if(rule.condition && rule.condition === "or"){
+ ruleResult = ruleResult || previousResult;
+ }
+ previousResult = ruleResult;
+ if (result === true && ruleResult !== true) {
+ result = getInputErrorMessage(input, rule.name) ||
+ getInputErrorMessage(this, rule.name) || false;
+ }
+ });
+ return result;
+ };
+ }
_compileValidationRules(input, ruleProp) {
- let rules = ruleProp.split(',').map(rule => {
+ let deliminator =',';
+ let andCondition =true;
+ // set the deliminator
+ if(ruleProp.indexOf('|')>0){
+
+ deliminator='|';
+ andCondition=false;
+ }
+ // Split and groups
+ let rules = ruleProp.split(deliminator).map(rule => {
let params = rule.split(':');
let name = params.shift();
let inverse = name[0] === '!';
@@ -257,14 +318,14 @@ export default class Form extends InputContainer {
name = name.substr(1);
}
- return { name, inverse, params };
+ return { name, inverse, params,andCondition:andCondition };
});
let validator = (input.props && input.props.type) === 'file' ? FileValidator : Validator;
return val => {
let result = true;
-
+ let previousResult = true;
rules.forEach(rule => {
if (typeof validator[rule.name] !== 'function') {
throw new Error('Invalid input validation rule "' + rule.name + '"');
@@ -275,6 +336,10 @@ export default class Form extends InputContainer {
if (rule.inverse) {
ruleResult = !ruleResult;
}
+ if(!rule.andCondition){
+ ruleResult = ruleResult || previousResult;
+ }
+ previousResult = ruleResult;
if (result === true && ruleResult !== true) {
result = getInputErrorMessage(input, rule.name) ||
diff --git a/src/Validator.js b/src/Validator.js
index 0e267e9..17286fe 100644
--- a/src/Validator.js
+++ b/src/Validator.js
@@ -6,19 +6,21 @@ import validator from 'validator';
* @params {String} val
* @returns {Boolean}
*/
-validator.extend('required', val => !validator.isNull(val));
+validator.required = (val) => !validator.isNull(val);
+validator.isEmpty = (val) => validator.isNull(val);
+
/**
* Returns true if the value is boolean true
*
* @params {String} val
* @returns {Boolean}
*/
-validator.extend('isChecked', val => {
+validator.isChecked = (val) => {
// compare it against string representation of a bool value, because
// validator ensures all incoming values are coerced to strings
// https://github.com/chriso/validator.js#strings-only
return val === 'true';
-});
+};
export default validator;