Some fields in our forms consist of multiple inputs that should group to a single value. For example, a date field that consists of a day, month and year inputs.
The redux-form solution
The redux-form library has a component called FormSection
that groups multiple inputs into one section. This solves part of our problem: it groups the inputs
under a common name. For example, year, month and day fields in a FieldSection named dayOfBirth
will dynamically be renamed to dayOfBirth.year, dayOfBirth.month and dayOfBirth.day. However,
it does not combine these values into a single value for form validation and submission. They are
still completely separate inputs. The CompositeInput component is build around FormSection
to provide this functionality.
The enhanced-redux-form CompositeInput component
The example below uses the CompositeInput component to group 2 separate fields (feet and inches)
into a single field called height.
<CompositeInput name="height" formatter={compositeInputFormatters.FEET_INCHES}>
<EnhancedField component={Input} type="number" step="1" placeholder="feet" name="feet" />
<EnhancedField component={Input} type="number" step="1" placeholder="inches" name="inches" />
</CompositeInput>
To redux-form, the feet and inches inputs are still separate fields. These fields will be
combined into a single value by enhanced-redux-form before running validation and passing the values
to the onSubmit handler. These values are combined by the FEET_INCHES formatter defined inside
compositeInputFormatters.js. All formatter functions need to be defined in this module in order
for enhanced-redux-form to find them. Below is an example of what this formatter might look like:
// compositeInputFormatters.js
const formatters = {
...
FEET_INCHES: ({feet, inches}) => {
const feet = parseInt(feet, 10);
const inches = parseInt(inches, 10);
return feet + (inches / 12);
}
...
}
Throwing validation errors in formatters
In our validation config (see Adding validation) we can now validate
our height value in inches. However, what if the values for feet or inches are invalid before
they reach the formatter? In this case, we can use the special error type CompositeInputFormatterError
to trigger a validation error back to the user, and mark the height field as invalid. Below is
the FEET_INCHES formatter with additional validation checks on the individual values.
// compositeInputFormatters.js
const formatters = {
...
FEET_INCHES: ({feet, inches}) => {
const feet = parseInt(feet, 10);
const inches = parseInt(inches, 10);
if (isNaN(feet)) {
// triggers a validation error on the 'feet' input
throw new CompositeInputFormatterError({ feet: 'Feet should be a number' });
}
if (isNaN(inches)) {
// triggers a validation error on the 'inches' input
throw new CompositeInputFormatterError({ inches: 'Inches should be a number' });
}
if (inches >= 12) {
// triggers a validation error on the 'inches' input
throw new CompositeInputFormatterError({ inches: 'Inches should be smaller than 12' });
}
const result = feet + (inches / 12);
if (result < 0) {
// triggers a general validation error on the CompositeInput
throw new CompositeInputFormatterError('This value cannot be negative!');
}
return result;
}
...
}