Skip to content

Commit d45adfd

Browse files
committed
feat(forms): allow objects as FormSelect value
1 parent 575bab9 commit d45adfd

File tree

3 files changed

+56
-18
lines changed

3 files changed

+56
-18
lines changed

demo/FormExamples.jsx

+10-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
export function FormExamples() {
1515
return (
1616
<Form
17-
initialValues={{ textField: 'abc' }}
17+
initialValues={{ textField: 'abc', selectField2: { e: 2, c: 'b' } }}
1818
onChange={console.info}
1919
onSubmit={(formData, reset) => {
2020
console.log('onSubmit', formData);
@@ -157,7 +157,7 @@ export function FormExamples() {
157157
options={[
158158
{ label: 'A', value: 'a' },
159159
{ label: 'B', value: 'b' },
160-
{ label: 'C', value: 'c' },
160+
{ label: 'C', value: 'd' },
161161
]}
162162
required
163163
/>
@@ -177,15 +177,14 @@ export function FormExamples() {
177177
<div className="col">
178178
<FormGroupSelect
179179
name="selectField4"
180-
label="Select field 4 (function)"
181-
options={(formData) =>
182-
Object.entries(formData)
183-
.filter(([key]) => key !== 'selectField4')
184-
.map(([key, value]) => ({
185-
label: key,
186-
value,
187-
}))
188-
}
180+
label="Select field 4 (objects with trackBy)"
181+
options={[
182+
{ label: 'A', value: { c: 'a', e: 1 } },
183+
{ label: 'B', value: { c: 'b', e: 2 } },
184+
{ label: 'C', value: { c: 'd', e: 3 } },
185+
]}
186+
trackBy="c"
187+
required
189188
/>
190189
</div>
191190
</div>

src/forms/FormSelect.jsx

+34-6
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,25 @@ import React, { useCallback } from 'react';
22
import PropTypes from 'prop-types';
33
import { normalizeOptions } from './helpers/form-helpers';
44
import { useFormControl } from './helpers/useFormControl';
5+
import { getValueByPath } from '../utils/getters-setters';
56

6-
export function FormSelect({ id, name, options, required, placeholder }) {
7+
export function FormSelect({ id, name, options, required, placeholder, trackBy }) {
78
const { getFormData, getValue, handleOnChange, register } = useFormControl(name);
89
const registerRef = useCallback(register, []);
10+
const value = getValue();
11+
const normalizedOptions = normalizeOptions(options, getFormData());
912

1013
return (
1114
<select
1215
{...{ required, name, id }}
1316
className="custom-select"
1417
onChange={handleOnChange}
15-
value={getValue()}
18+
value={getSelectedOption(value, normalizedOptions, trackBy)}
1619
ref={registerRef}
1720
>
1821
<option value="">{placeholder}</option>
1922

20-
{renderOptions(options, getFormData())}
23+
{renderOptions(normalizedOptions, trackBy)}
2124
</select>
2225
);
2326
}
@@ -31,12 +34,37 @@ FormSelect.propTypes = {
3134
]),
3235
placeholder: PropTypes.string,
3336
required: PropTypes.any,
37+
trackBy: PropTypes.string,
3438
};
3539

36-
function renderOptions(options, formData) {
37-
return normalizeOptions(options, formData).map(({ value, label }, index) => (
38-
<option key={index} value={value}>
40+
function renderOptions(options, trackBy) {
41+
return options.map(({ value, label }, index) => (
42+
<option key={index} name={trackBy} value={serializeValue(value)}>
3943
{label}
4044
</option>
4145
));
4246
}
47+
48+
function getSelectedOption(value, options, trackBy) {
49+
let selectedValue = value;
50+
51+
if (trackBy) {
52+
const selectedOption = options.find(
53+
(option) => getValueByPath(option.value, trackBy) === getValueByPath(value, trackBy)
54+
);
55+
56+
if (selectedOption) {
57+
selectedValue = selectedOption.value;
58+
}
59+
}
60+
61+
return serializeValue(selectedValue);
62+
}
63+
64+
function serializeValue(value) {
65+
if (typeof value !== 'object') {
66+
return value;
67+
}
68+
69+
return JSON.stringify(value);
70+
}

src/forms/helpers/useFormControl.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,18 @@ export function useFormControl(name, type) {
1212
getValue: () => formState.getValue(name) || getEmptyValue(type),
1313
setValue,
1414
handleOnChange: ({ target }) => {
15-
const value = target.type === 'checkbox' ? target.checked : target.value;
15+
let value = target.type === 'checkbox' ? target.checked : target.value;
16+
17+
if (target.type === 'select-one') {
18+
if (value && ['{', '['].includes(value[0])) {
19+
try {
20+
value = JSON.parse(value);
21+
} catch (error) {
22+
// eslint-disable-next-line no-console
23+
console.error(error);
24+
}
25+
}
26+
}
1627

1728
setValue(value);
1829
},

0 commit comments

Comments
 (0)