Skip to content

Commit 12bad02

Browse files
authored
Merge pull request #377 from data-driven-forms/data-conversion-of-initial-value
fix(renderer): convert initialValue dataType
2 parents 221189d + 063dd8d commit 12bad02

File tree

6 files changed

+110
-8
lines changed

6 files changed

+110
-8
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { convertType } from './enhanced-on-change';
2+
3+
const convertInitialValue = (initialValue, dataType) => {
4+
if (initialValue === undefined || !dataType) {
5+
return initialValue;
6+
}
7+
8+
if (Array.isArray(initialValue)) {
9+
return initialValue.map(value => typeof value === 'object' ? ({
10+
...value,
11+
value: Object.prototype.hasOwnProperty.call(value, 'value') ? convertType(dataType, value.value) : value,
12+
}) : convertType(dataType, value));
13+
}
14+
15+
return convertType(dataType, initialValue);
16+
};
17+
18+
export default convertInitialValue;

packages/react-form-renderer/src/form-renderer/enhanced-on-change.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const castToBoolean = value => {
3434
* @param {FieldDataTypes} dataType type for value conversion
3535
* @param {Any} value value to be converted
3636
*/
37-
const convertType = (dataType, value) => ({
37+
export const convertType = (dataType, value) => ({
3838
[dataTypes.INTEGER]: !isNaN(Number(value)) && parseInt(value),
3939
[dataTypes.FLOAT]: !isNaN(Number(value)) && parseFloat(value),
4040
[dataTypes.NUMBER]: Number(value),

packages/react-form-renderer/src/form-renderer/field-wrapper.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,30 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import { FormSpy } from 'react-final-form';
44

5-
import { components } from '../constants';
5+
import { components, dataTypes } from '../constants';
66
import FieldProvider from './field-provider';
77
import { FieldArray } from 'react-final-form-arrays';
88
import { shouldWrapInField, composeValidators } from './helpers';
9+
import convertInitialValue from './convert-initial-value';
910

1011
const shouldAssignFormOptions = componentType => components.FIELD_ARRAY === componentType;
1112
const assignSpecialType = componentType => [ components.CHECKBOX, components.RADIO ].includes(componentType) ? componentType : undefined;
1213

1314
const FieldWrapper = ({ componentType, validate, component, ...rest }) => {
15+
const props = rest;
16+
17+
if (Object.prototype.hasOwnProperty.call(rest, 'initialValue') && Object.prototype.hasOwnProperty.call(rest, 'dataType')) {
18+
props.initialValue = convertInitialValue(rest.initialValue, rest.dataType);
19+
}
20+
1421
const componentProps = {
1522
type: assignSpecialType(componentType),
1623
FieldProvider,
1724
FieldArrayProvider: FieldArray,
18-
...rest,
25+
...props,
1926
component,
2027
};
28+
2129
if (shouldAssignFormOptions(componentType)) {
2230
componentProps.arrayValidator = (value = []) => {
2331
if (!Array.isArray(value)) {
@@ -39,17 +47,25 @@ const FieldWrapper = ({ componentType, validate, component, ...rest }) => {
3947
const Component = component;
4048
return shouldWrapInField(componentType)
4149
? <FieldProvider { ...componentProps } />
42-
: <Component validate={ composeValidators(validate) } { ...rest } FieldProvider={ FieldProvider } FormSpyProvider={ FormSpy } />;
50+
: (
51+
<Component
52+
validate={ composeValidators(validate) }
53+
{ ...props }
54+
FieldProvider={ FieldProvider }
55+
FormSpyProvider={ FormSpy }
56+
/>);
4357
};
4458

4559
FieldWrapper.propTypes = {
4660
componentType: PropTypes.string,
4761
validate: PropTypes.arrayOf(PropTypes.func),
62+
initialValue: PropTypes.any,
4863
component: PropTypes.oneOfType([
4964
PropTypes.node,
5065
PropTypes.func,
5166
PropTypes.element,
5267
]).isRequired,
68+
dataType: PropTypes.oneOf(dataTypes),
5369
};
5470

5571
export default FieldWrapper;

packages/react-form-renderer/src/tests/form-renderer/__snapshots__/form-renderer.test.js.snap

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ exports[`<FormRenderer /> should render form from schema 1`] = `
8181
<Component
8282
onSubmit={[Function]}
8383
>
84-
<form>
84+
<form
85+
onSubmit={[Function]}
86+
>
8587
<FormConditionWrapper>
8688
<FormFieldHideWrapper
8789
hideField={false}
@@ -897,7 +899,9 @@ exports[`<FormRenderer /> should render hidden field 1`] = `
897899
<Component
898900
onSubmit={[Function]}
899901
>
900-
<form>
902+
<form
903+
onSubmit={[Function]}
904+
>
901905
<FormConditionWrapper>
902906
<FormFieldHideWrapper
903907
hideField={false}

packages/react-form-renderer/src/tests/form-renderer/form-renderer.test.js

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('<FormRenderer />', () => {
3131
layoutMapper = {
3232
[layoutComponents.BUTTON_GROUP]: ({ children }) => <div>{ children }</div>,
3333
[layoutComponents.BUTTON]: ({ label, bsStyle, ...rest }) => <button { ...rest }>{ label }</button>,
34-
[layoutComponents.FORM_WRAPPER]: ({ children }) => <form>{ children }</form>,
34+
[layoutComponents.FORM_WRAPPER]: ({ children, ...props }) => <form { ...props }>{ children }</form>,
3535
[layoutComponents.TITLE]: ({ children }) => <div>{ children }</div>,
3636
[layoutComponents.DESCRIPTION]: ({ children }) => <div>{ children }</div>,
3737
};
@@ -150,5 +150,67 @@ describe('<FormRenderer />', () => {
150150
/>);
151151
expect(toJson(wrapper)).toMatchSnapshot();
152152
});
153+
154+
describe('Initial value data types', () => {
155+
it('should convert string to integer', () => {
156+
const onSubmit = jest.fn();
157+
const schema = {
158+
fields: [{
159+
component: components.TEXT_FIELD,
160+
name: 'initial-convert',
161+
initialValue: '5',
162+
dataType: 'integer',
163+
}],
164+
};
165+
const wrapper = mount(<FormRenderer
166+
{ ...initialProps }
167+
schema={ schema }
168+
onSubmit={ values => onSubmit(values) }
169+
renderFormButtons={ FormControls }
170+
/>);
171+
wrapper.find('form').simulate('submit');
172+
expect(onSubmit).toHaveBeenCalledWith({ 'initial-convert': 5 });
173+
});
174+
175+
it('should convert individual values in array of literals as initial value', () => {
176+
const onSubmit = jest.fn();
177+
const schema = {
178+
fields: [{
179+
component: components.TEXT_FIELD,
180+
name: 'initial-convert',
181+
initialValue: [ '5', 3, '11', '999' ],
182+
dataType: 'integer',
183+
}],
184+
};
185+
const wrapper = mount(<FormRenderer
186+
{ ...initialProps }
187+
schema={ schema }
188+
onSubmit={ values => onSubmit(values) }
189+
renderFormButtons={ FormControls }
190+
/>);
191+
wrapper.find('form').simulate('submit');
192+
expect(onSubmit).toHaveBeenCalledWith({ 'initial-convert': [ 5, 3, 11, 999 ]});
193+
});
194+
195+
it('should convert individual values in array of objects as initial value', () => {
196+
const onSubmit = jest.fn();
197+
const schema = {
198+
fields: [{
199+
component: components.SELECT,
200+
name: 'initial-convert',
201+
initialValue: [{ value: '5' }, { value: 3 }, { value: '11' }, { value: '999' }],
202+
dataType: 'integer',
203+
}],
204+
};
205+
const wrapper = mount(<FormRenderer
206+
{ ...initialProps }
207+
schema={ schema }
208+
onSubmit={ values => onSubmit(values) }
209+
renderFormButtons={ FormControls }
210+
/>);
211+
wrapper.find('form').simulate('submit');
212+
expect(onSubmit).toHaveBeenCalledWith({ 'initial-convert': [{ value: 5 }, { value: 3 }, { value: 11 }, { value: 999 }]});
213+
});
214+
});
153215
});
154216

packages/react-form-renderer/src/validators/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ export const pattern = memoize(({ pattern, message, flags } = {}) => {
5252

5353
if (Array.isArray(value)) {
5454
const error = value.find(item => {
55-
const parsedValue = typeof item === 'string' ? item : item.toString();
55+
const parsedValue = typeof item === 'object' && Object.prototype.hasOwnProperty.call(item, 'value')
56+
? item.value.toString()
57+
: typeof item === 'string' ? item : item.toString();
5658
return pattern && !parsedValue.match(verifiedPattern);
5759
});
5860
const msg = prepareMsg(message, 'pattern').defaultMessage;

0 commit comments

Comments
 (0)