Skip to content

Commit d44abed

Browse files
committed
feat(forms): implement proper afterChange callback
1 parent ed0f20c commit d44abed

9 files changed

+106
-32
lines changed

demo/FormExamples.jsx

+23-3
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,13 @@ export function FormExamples() {
109109
<FormGroupInput name="textField" label="Text field" disabled help="Text field help" />
110110
</div>
111111
<div className="col">
112-
<FormGroupInput name="textField2" label="Text field 2" required placeholder="Fill some value" />
112+
<FormGroupInput
113+
name="textField2"
114+
label="Text field 2"
115+
required
116+
placeholder="Fill some value"
117+
afterChange={console.log.bind(console, 'afterChange input')}
118+
/>
113119
</div>
114120
<div className="col">
115121
<FormGroupInput
@@ -150,6 +156,7 @@ export function FormExamples() {
150156
placeholder="Type some letters"
151157
openOnFocus={true}
152158
required={() => true}
159+
afterChange={console.log.bind(console, 'afterChange autocomplete')}
153160
/>
154161
</div>
155162
<div className="col">
@@ -182,7 +189,12 @@ export function FormExamples() {
182189
/>
183190
</div>
184191
<div className="col-4">
185-
<FormGroupSelect name="selectNumberField" label="Select field (number list)" options={[1, 2, 3, 4]} />
192+
<FormGroupSelect
193+
name="selectNumberField"
194+
label="Select field (number list)"
195+
afterChange={console.log.bind(console, 'afterChange select')}
196+
options={[1, 2, 3, 4]}
197+
/>
186198
</div>
187199
<div className="col-4">
188200
<FormGroupSelect
@@ -243,6 +255,7 @@ export function FormExamples() {
243255
trueLabel="ON"
244256
falseLabel="OFF"
245257
help="Switch help"
258+
afterChange={console.log.bind(console, 'afterChange switch')}
246259
/>
247260
</div>
248261
<div className="col">
@@ -255,6 +268,7 @@ export function FormExamples() {
255268
label="Checkbox field"
256269
valueLabel="Checkbox description"
257270
help="Checkbox help"
271+
afterChange={console.log.bind(console, 'afterChange checkbox')}
258272
/>
259273
</div>
260274
<div className="col">
@@ -280,6 +294,7 @@ export function FormExamples() {
280294
},
281295
]}
282296
help="Radio help"
297+
afterChange={console.log.bind(console, 'afterChange radio')}
283298
/>
284299
</div>
285300
<div className="col">
@@ -302,7 +317,12 @@ export function FormExamples() {
302317
</div>
303318
</div>
304319

305-
<FormGroupTextarea name="textareaField" label="Textarea field" help="Textarea help" />
320+
<FormGroupTextarea
321+
name="textareaField"
322+
label="Textarea field"
323+
help="Textarea help"
324+
afterChange={console.log.bind(console, 'afterChange textarea')}
325+
/>
306326
<FormGroupTextarea name="textareaField2" label="Textarea field 2" disabled rows="1" />
307327

308328
{[0, 1].map((index) => (

src/forms/FormAutocomplete.jsx

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useRef, useCallback, useEffect, useMemo } from 'react';
22
import PropTypes from 'prop-types';
3-
import { isEmptyLike } from 'js-var-type';
3+
import { isEmptyLike, isFunction } from 'js-var-type';
44

55
import { handleInputChange, normalizeOptions, booleanOrFunction } from './helpers/form-helpers';
66
import { Dropdown } from '../mixed/Dropdown';
@@ -20,10 +20,23 @@ export function FormAutocomplete({
2020
template,
2121
filter,
2222
disabled: _disabled,
23+
afterChange,
2324
}) {
24-
const { getValue, setValue, register, isValid, getFormSubmitedAttempted, getFormData } = useFormControl(name);
25+
const { getValue, setValue: _setValue, register, isValid, getFormSubmitedAttempted, getFormData } = useFormControl(
26+
name
27+
);
2528
const value = getValue();
2629

30+
const setValue = useCallback(
31+
(v) => {
32+
_setValue(v);
33+
if (isFunction(afterChange)) {
34+
afterChange(v);
35+
}
36+
},
37+
[_setValue, afterChange]
38+
);
39+
2740
const [searchValue, setSearchValue] = useState('');
2841
const items = normalizeOptions(options, getFormData(), searchValue);
2942
const _selectedItem = items.find((item) => item.value === value);
@@ -187,6 +200,7 @@ FormAutocomplete.defaultProps = {
187200
};
188201

189202
FormAutocomplete.propTypes = {
203+
afterChange: PropTypes.func,
190204
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
191205
filter: PropTypes.func,
192206
id: PropTypes.string,
@@ -212,6 +226,7 @@ export function FormGroupAutocomplete(props) {
212226
}
213227

214228
FormGroupAutocomplete.propTypes = {
229+
afterChange: PropTypes.func,
215230
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
216231
filter: PropTypes.func,
217232
help: PropTypes.node,

src/forms/FormCheckbox.jsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { useFormControl } from './helpers/useFormControl';
55
import { booleanOrFunction } from './helpers/form-helpers';
66
import { FormGroup } from './FormGroup';
77

8-
export function FormCheckbox({ id, name, required: _required, valueLabel, disabled: _disabled }) {
9-
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, 'boolean');
8+
export function FormCheckbox({ id, name, required: _required, valueLabel, disabled: _disabled, afterChange }) {
9+
const { getValue, handleOnChangeFactory, register, getFormData } = useFormControl(name, 'boolean');
1010
const registerRef = useCallback(register, [register]);
1111
const disabled = booleanOrFunction(_disabled, getFormData());
1212
const required = booleanOrFunction(_required, getFormData());
@@ -17,7 +17,7 @@ export function FormCheckbox({ id, name, required: _required, valueLabel, disabl
1717
{...{ required, name, id, disabled }}
1818
type="checkbox"
1919
className="custom-control-input"
20-
onChange={handleOnChange}
20+
onChange={handleOnChangeFactory(afterChange)}
2121
checked={getValue()}
2222
ref={registerRef}
2323
/>
@@ -29,11 +29,12 @@ export function FormCheckbox({ id, name, required: _required, valueLabel, disabl
2929
}
3030

3131
FormCheckbox.propTypes = {
32+
afterChange: PropTypes.func,
33+
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3234
id: PropTypes.string.isRequired,
3335
name: PropTypes.string.isRequired,
34-
valueLabel: PropTypes.node,
3536
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
36-
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
37+
valueLabel: PropTypes.node,
3738
};
3839

3940
export function FormGroupCheckbox(props) {
@@ -45,6 +46,7 @@ export function FormGroupCheckbox(props) {
4546
}
4647

4748
FormGroupCheckbox.propTypes = {
49+
afterChange: PropTypes.func,
4850
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
4951
falseLabel: PropTypes.node,
5052
help: PropTypes.node,

src/forms/FormInput.jsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { useFormControl } from './helpers/useFormControl';
55
import { booleanOrFunction } from './helpers/form-helpers';
66
import { FormGroup } from './FormGroup';
77

8-
export function FormInput({ type, name, required: _required, disabled: _disabled, ..._attrs }) {
9-
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, type);
8+
export function FormInput({ type, name, required: _required, disabled: _disabled, afterChange, ..._attrs }) {
9+
const { getValue, handleOnChangeFactory, register, getFormData } = useFormControl(name, type);
1010
const registerRef = useCallback(register, [register]);
1111
const disabled = booleanOrFunction(_disabled, getFormData());
1212
const required = booleanOrFunction(_required, getFormData());
@@ -25,14 +25,15 @@ export function FormInput({ type, name, required: _required, disabled: _disabled
2525
attrs.value = getValue();
2626
}
2727

28-
return <input {...attrs} className="form-control" onChange={handleOnChange} ref={registerRef} />;
28+
return <input {...attrs} className="form-control" onChange={handleOnChangeFactory(afterChange)} ref={registerRef} />;
2929
}
3030

3131
FormInput.defaultProps = {
3232
type: 'text',
3333
};
3434

3535
FormInput.propTypes = {
36+
afterChange: PropTypes.func,
3637
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3738
id: PropTypes.string,
3839
max: PropTypes.string,
@@ -57,6 +58,7 @@ export function FormGroupInput(props) {
5758
}
5859

5960
FormGroupInput.propTypes = {
61+
afterChange: PropTypes.func,
6062
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
6163
help: PropTypes.node,
6264
id: PropTypes.string,

src/forms/FormRadio.jsx

+14-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@ import { booleanOrFunction } from './helpers/form-helpers';
66
import { formatClasses } from '../utils/attributes';
77
import { FormGroup } from './FormGroup';
88

9-
export function FormRadio({ id, name, required: _required, checkedValue, valueLabel, inline, disabled: _disabled }) {
10-
const { getValue, handleOnChange, register, getFormData } = useFormControl(name);
9+
export function FormRadio({
10+
id,
11+
name,
12+
required: _required,
13+
checkedValue,
14+
valueLabel,
15+
inline,
16+
disabled: _disabled,
17+
afterChange,
18+
}) {
19+
const { getValue, handleOnChangeFactory, register, getFormData } = useFormControl(name);
1120
const registerRef = useCallback(register, [register]);
1221
const value = getValue();
1322
const disabled = booleanOrFunction(_disabled, getFormData());
@@ -19,7 +28,7 @@ export function FormRadio({ id, name, required: _required, checkedValue, valueLa
1928
{...{ required, name, id, disabled }}
2029
type="radio"
2130
className="custom-control-input"
22-
onChange={handleOnChange}
31+
onChange={handleOnChangeFactory(afterChange)}
2332
checked={value === checkedValue}
2433
value={checkedValue}
2534
ref={registerRef}
@@ -36,6 +45,7 @@ FormRadio.defaultProps = {
3645
};
3746

3847
FormRadio.propTypes = {
48+
afterChange: PropTypes.func,
3949
checkedValue: PropTypes.any,
4050
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
4151
id: PropTypes.string.isRequired,
@@ -68,6 +78,7 @@ FormGroupRadio.defaultProps = {
6878
};
6979

7080
FormGroupRadio.propTypes = {
81+
afterChange: PropTypes.func,
7182
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
7283
help: PropTypes.node,
7384
id: PropTypes.string,

src/forms/FormSelect.jsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ export function FormSelect({
1818
placeholder,
1919
trackBy,
2020
disabled: _disabled,
21+
afterChange,
2122
..._attrs
2223
}) {
23-
const { getFormData, getValue, handleOnChange, register } = useFormControl(name);
24+
const { getFormData, getValue, handleOnChangeFactory, register } = useFormControl(name);
2425
const registerRef = useCallback(register, [register]);
2526
const value = getValue();
2627
const normalizedOptions = normalizeOptions(options, getFormData());
@@ -38,7 +39,7 @@ export function FormSelect({
3839
<select
3940
{...attrs}
4041
className="custom-select"
41-
onChange={(e) => handleOnChange(e, getOptionsType(normalizedOptions))}
42+
onChange={handleOnChangeFactory(afterChange, getOptionsType(normalizedOptions))}
4243
value={getSelectedOption(value, normalizedOptions, trackBy)}
4344
ref={registerRef}
4445
>
@@ -50,6 +51,7 @@ export function FormSelect({
5051
}
5152

5253
FormSelect.propTypes = {
54+
afterChange: PropTypes.func,
5355
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
5456
id: PropTypes.string,
5557
name: PropTypes.string.isRequired,
@@ -77,6 +79,7 @@ export function FormGroupSelect(props) {
7779
}
7880

7981
FormGroupSelect.propTypes = {
82+
afterChange: PropTypes.func,
8083
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
8184
help: PropTypes.node,
8285
id: PropTypes.string,

src/forms/FormSwitch.jsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { useFormControl } from './helpers/useFormControl';
55
import { booleanOrFunction } from './helpers/form-helpers';
66
import { FormGroup } from './FormGroup';
77

8-
export function FormSwitch({ id, name, required: _required, trueLabel, falseLabel, disabled: _disabled }) {
9-
const { getValue, handleOnChange, register, getFormData } = useFormControl(name, 'boolean');
8+
export function FormSwitch({ id, name, required: _required, trueLabel, falseLabel, disabled: _disabled, afterChange }) {
9+
const { getValue, handleOnChangeFactory, register, getFormData } = useFormControl(name, 'boolean');
1010
const registerRef = useCallback(register, [register]);
1111
const value = getValue();
1212
const disabled = booleanOrFunction(_disabled, getFormData());
@@ -18,7 +18,7 @@ export function FormSwitch({ id, name, required: _required, trueLabel, falseLabe
1818
{...{ required, name, id, disabled }}
1919
type="checkbox"
2020
className="custom-control-input"
21-
onChange={handleOnChange}
21+
onChange={handleOnChangeFactory(afterChange)}
2222
checked={value}
2323
ref={registerRef}
2424
/>
@@ -30,6 +30,7 @@ export function FormSwitch({ id, name, required: _required, trueLabel, falseLabe
3030
}
3131

3232
FormSwitch.propTypes = {
33+
afterChange: PropTypes.func,
3334
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3435
falseLabel: PropTypes.node,
3536
id: PropTypes.string.isRequired,
@@ -47,6 +48,7 @@ export function FormGroupSwitch(props) {
4748
}
4849

4950
FormGroupSwitch.propTypes = {
51+
afterChange: PropTypes.func,
5052
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
5153
falseLabel: PropTypes.node,
5254
help: PropTypes.node,

src/forms/FormTextarea.jsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { useFormControl } from './helpers/useFormControl';
55
import { booleanOrFunction } from './helpers/form-helpers';
66
import { FormGroup } from './FormGroup';
77

8-
export function FormTextarea({ name, required: _required, disabled: _disabled, ..._attrs }) {
9-
const { getValue, handleOnChange, register, getFormData } = useFormControl(name);
8+
export function FormTextarea({ name, required: _required, disabled: _disabled, afterChange, ..._attrs }) {
9+
const { getValue, handleOnChangeFactory, register, getFormData } = useFormControl(name);
1010
const registerRef = useCallback(register, [register]);
1111
const disabled = booleanOrFunction(_disabled, getFormData());
1212
const required = booleanOrFunction(_required, getFormData());
@@ -22,7 +22,7 @@ export function FormTextarea({ name, required: _required, disabled: _disabled, .
2222
<textarea
2323
{...attrs}
2424
className="form-control"
25-
onChange={handleOnChange}
25+
onChange={handleOnChangeFactory(afterChange)}
2626
value={getValue()}
2727
ref={registerRef}
2828
></textarea>
@@ -34,6 +34,7 @@ FormTextarea.defaultProps = {
3434
};
3535

3636
FormTextarea.propTypes = {
37+
afterChange: PropTypes.func,
3738
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
3839
id: PropTypes.string,
3940
name: PropTypes.string.isRequired,
@@ -52,6 +53,7 @@ export function FormGroupTextarea(props) {
5253
}
5354

5455
FormGroupTextarea.propTypes = {
56+
afterChange: PropTypes.func,
5557
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
5658
help: PropTypes.node,
5759
id: PropTypes.string,

0 commit comments

Comments
 (0)