Skip to content

Commit c1d294d

Browse files
authored
Merge pull request #199 from data-driven-forms/multi-field-validation
Multi field validation
2 parents 8b041de + 38cd623 commit c1d294d

File tree

8 files changed

+1314
-275
lines changed

8 files changed

+1314
-275
lines changed

packages/react-form-renderer/demo/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const submitTest = (...args) => new Promise(resolve => {
1616
})
1717

1818
const FormButtons = props => {
19-
console.log('form buttons props', props)
2019
return (
2120
<div>
2221
<button disabled={props.submitting} type="button" onClick={props.form.submit}>Submit</button>

packages/react-form-renderer/demo/sandbox.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,33 @@ const output = {
77
fields: [
88
{
99
name: 'text_box_1',
10-
label: 'Text Box',
10+
label: 'Text Box 1',
1111
title: 'Text Box',
1212
component: components.TEXT_FIELD,
1313
},
14+
{
15+
name: 'text_box_1_condition',
16+
label: 'Text Box conditional',
17+
title: 'Text Box',
18+
component: components.TEXT_FIELD,
19+
condition: [{
20+
when: [ 'text_box_1', 'text_box_4' ],
21+
is: 'a',
22+
}, {
23+
when: 'text_box_3',
24+
is: 'x',
25+
}],
26+
},
1427
{
1528
name: 'text_box_2',
16-
label: 'Text Box with help',
17-
title: 'Text Box with help',
29+
label: 'Text Box 2',
1830
helperText: 'Helper text',
1931
component: components.TEXT_FIELD,
2032
hideField: true,
2133
},
2234
{
2335
name: 'text_box_3',
24-
label: 'Text Box required',
25-
title: 'Text Box required',
36+
label: 'Text Box 3',
2637
isRequired: true,
2738
component: components.TEXT_FIELD,
2839
validate: [
@@ -31,16 +42,18 @@ const output = {
3142
},
3243
{
3344
name: 'text_box_4',
34-
label: 'Text Box readonly',
35-
title: 'Text Box readonly',
45+
label: 'Text Box 4',
3646
isReadOnly: true,
3747
component: components.TEXT_FIELD,
3848
},
3949
{
40-
name: 'text_box_5',
41-
label: 'Text Box default',
42-
title: 'Text Box default',
50+
name: 'foo',
51+
label: 'Uaaaaaaaaaaaaaaaaa',
4352
component: components.TEXT_FIELD,
53+
condition: {
54+
when: 'text_box_1',
55+
is: 'a',
56+
},
4457
},
4558
{
4659
name: 'text_box_6',

packages/react-form-renderer/src/form-renderer/condition.js

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import { isEmpty as lodashIsEmpty } from 'lodash';
4-
import { Field } from 'react-final-form';
4+
import { FormSpy } from 'react-final-form';
55

66
const isEmptyValue = (value) => typeof value === 'number' || value === true ? false : lodashIsEmpty(value);
77

8-
const Condition = ({ when, is, isNotEmpty, isEmpty, children, pattern, notMatch }) => {
9-
const shouldRender = value => {
8+
const Condition = ({ condition, children }) => {
9+
const fieldCondition = (value, { is, isNotEmpty, isEmpty, pattern, notMatch }) => {
1010
if (isNotEmpty){
1111
return !isEmptyValue(value);
1212
}
@@ -24,14 +24,33 @@ const Condition = ({ when, is, isNotEmpty, isEmpty, children, pattern, notMatch
2424
return notMatch ? !isMatched : isMatched;
2525
};
2626

27+
const shouldRender = (values, conditionItem) => {
28+
if (typeof conditionItem.when === 'string') {
29+
return fieldCondition(values[conditionItem.when], conditionItem);
30+
}
31+
32+
if (Array.isArray(conditionItem.when)) {
33+
return conditionItem.when.map(fieldName => fieldCondition(values[fieldName], conditionItem)).find(condition => !!condition);
34+
}
35+
36+
return false;
37+
};
38+
2739
return (
28-
<Field name={ when } subscription={{ value: true }}>
29-
{ ({ input: { value }}) => (shouldRender(value) ? children : null) }
30-
</Field>
40+
<FormSpy>
41+
{ ({ values }) => {
42+
const visible = Array.isArray(condition)
43+
? !condition.map(conditionItem => !!shouldRender(values, conditionItem)).some(result => result === false)
44+
: shouldRender(values, condition);
45+
46+
return visible ? children : null;
47+
} }
48+
</FormSpy>
3149
);
50+
3251
};
3352

34-
Condition.propTypes = {
53+
const conditionProps = {
3554
when: PropTypes.string.isRequired,
3655
is: PropTypes.oneOfType([
3756
PropTypes.array,
@@ -53,4 +72,15 @@ Condition.propTypes = {
5372
notMatch: PropTypes.any,
5473
};
5574

75+
Condition.propTypes = {
76+
condition: PropTypes.oneOfType([
77+
PropTypes.shape(conditionProps),
78+
PropTypes.arrayOf(PropTypes.shape(conditionProps)),
79+
]),
80+
children: PropTypes.oneOf([
81+
PropTypes.node,
82+
PropTypes.arrayOf(PropTypes.node),
83+
]).isRequired,
84+
};
85+
5686
export default Condition;

packages/react-form-renderer/src/form-renderer/render-form.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ FormFieldHideWrapper.defaultProps = {
2121
};
2222

2323
const FormConditionWrapper = ({ condition, children }) => (condition ? (
24-
<Condition { ...condition }>
24+
<Condition condition={ condition }>
2525
{ children }
2626
</Condition>
2727
) : children);

packages/react-form-renderer/src/parsers/default-schema-validator.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ const checkFieldsArray = (obj, objectKey) => {
1515
};
1616

1717
const checkCondition = (condition, fieldName) => {
18-
if (Array.isArray(condition) || typeof condition !== 'object') {
18+
/**
19+
* validate array condition
20+
*/
21+
if (Array.isArray(condition)) {
22+
return condition.forEach(item => checkCondition(item, fieldName));
23+
}
24+
25+
if (typeof condition !== 'object') {
1926
throw new DefaultSchemaError(`
2027
Error occured in field definition with name: "${fieldName}".
2128
Field condition must be an object, received ${Array.isArray(condition) ? 'array' : typeof condition}!
@@ -29,7 +36,7 @@ const checkCondition = (condition, fieldName) => {
2936
`);
3037
}
3138

32-
if (typeof condition.when !== 'string') {
39+
if (!(typeof condition.when === 'string' || Array.isArray(condition.when))) {
3340
throw new DefaultSchemaError(`
3441
Error occured in field definition with name: "${fieldName}".
3542
Field condition property "when" must be oof type "string", ${typeof condition.when} received!].

0 commit comments

Comments
 (0)