Skip to content

Commit e85a2f3

Browse files
Feature - (@rjsf/core) Reset form data, validations and errors (rjsf-team#3492)
* Reset function added to form / Test cases added * Clear validations and errors/ playground reset btn * Reset func description edit * Playground reset btn title edit * Test widgets schema edited file extention * Test description changed * Child ref declarations changed with createRef * Reset operations resetErrors func removed * 5.3.0 version CHANGELOG.md added --------- Co-authored-by: Heath C <51679588+heath-freenome@users.noreply.github.com>
1 parent 8ddff2d commit e85a2f3

File tree

5 files changed

+219
-0
lines changed

5 files changed

+219
-0
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ should change the heading of the (upcoming) version to include a major version b
1616
1717
-->
1818

19+
# 5.3.0
20+
21+
## @rjsf/core
22+
23+
- `Reset` function added for `Programmatically Reset` action. `Reset` function will reset form data and validation errors. Form data will set to default values.
24+
25+
## Dev / docs / playground
26+
27+
- Added `Programmatically Reset` button to clear states which are form data and validation errors.
28+
1929
# 5.2.1
2030

2131
## @rjsf/antd

packages/core/src/components/Form.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,27 @@ export default class Form<
535535
this.setState(state as FormState<T, S, F>, () => onChange && onChange({ ...this.state, ...state }, id));
536536
};
537537

538+
/**
539+
* Callback function to handle reset form data.
540+
* - Reset all fields with default values.
541+
* - Reset validations and errors
542+
*
543+
*/
544+
reset = () => {
545+
const { onChange } = this.props;
546+
const newState = this.getStateFromProps(this.props, undefined);
547+
const newFormData = newState.formData;
548+
const state = {
549+
formData: newFormData,
550+
errorSchema: {},
551+
errors: [] as unknown,
552+
schemaValidationErrors: [] as unknown,
553+
schemaValidationErrorSchema: {},
554+
} as FormState<T, S, F>;
555+
556+
this.setState(state, () => onChange && onChange({ ...this.state, ...state }));
557+
};
558+
538559
/** Callback function to handle when a field on the form is blurred. Calls the `onBlur` callback for the `Form` if it
539560
* was provided.
540561
*

packages/core/test/Form.test.jsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
describeRepeated,
1717
submitForm,
1818
} from './test_utils';
19+
import widgetsSchema from './widgets_schema.json';
1920

2021
describeRepeated('Form common', (createFormComponent) => {
2122
let sandbox;
@@ -3912,4 +3913,98 @@ describe('Form omitExtraData and liveOmit', () => {
39123913
expect(node.querySelector('#root_1').getAttribute('value')).to.eq('test');
39133914
});
39143915
});
3916+
3917+
describe('Calling reset from ref object', () => {
3918+
it('Reset API test', () => {
3919+
const schema = {
3920+
title: 'Test form',
3921+
type: 'string',
3922+
};
3923+
const formRef = React.createRef();
3924+
const props = {
3925+
ref: formRef,
3926+
schema,
3927+
};
3928+
const { node } = createFormComponent(props);
3929+
expect(formRef.current.reset).to.exist;
3930+
expect(node.querySelector('input')).to.exist;
3931+
Simulate.change(node.querySelector('input'), { target: { value: 'Some Value' } });
3932+
formRef.current.reset();
3933+
expect(node.querySelector('input').getAttribute('value')).to.eq('');
3934+
});
3935+
3936+
it('Clear errors', () => {
3937+
const schema = {
3938+
title: 'Test form',
3939+
type: 'number',
3940+
};
3941+
const formRef = React.createRef();
3942+
const props = {
3943+
ref: formRef,
3944+
schema,
3945+
};
3946+
const { node, comp } = createFormComponent(props);
3947+
expect(formRef.current.reset).to.exist;
3948+
expect(node.querySelector('input')).to.exist;
3949+
Simulate.change(node.querySelector('input'), { target: { value: 'Some Value' } });
3950+
expect(comp.state.errors).to.have.length(0);
3951+
Simulate.submit(node);
3952+
expect(comp.state.errors).to.have.length(1);
3953+
expect(node.querySelector('.errors')).to.exist;
3954+
formRef.current.reset();
3955+
expect(node.querySelector('.errors')).not.to.exist;
3956+
expect(node.querySelector('input').getAttribute('value')).to.eq('');
3957+
expect(comp.state.errors).to.have.length(0);
3958+
});
3959+
3960+
it('Reset button test with default value', () => {
3961+
const schemaWithDefault = {
3962+
title: 'Test form',
3963+
type: 'string',
3964+
default: 'Some-Value',
3965+
};
3966+
const formRef = React.createRef();
3967+
const props = {
3968+
ref: formRef,
3969+
schema: schemaWithDefault,
3970+
};
3971+
const { node } = createFormComponent(props);
3972+
const input = node.querySelector('input');
3973+
expect(formRef.current.reset).to.exist;
3974+
expect(input).to.exist;
3975+
expect(input.getAttribute('value')).to.eq('Some-Value');
3976+
formRef.current.reset();
3977+
expect(input.getAttribute('value')).to.eq('Some-Value');
3978+
Simulate.change(input, { target: { value: 'Changed value' } });
3979+
formRef.current.reset();
3980+
expect(input.getAttribute('value')).to.eq('Some-Value');
3981+
});
3982+
3983+
it('Reset button test with complex schema', () => {
3984+
const schema = widgetsSchema;
3985+
const formRef = React.createRef();
3986+
const props = {
3987+
ref: formRef,
3988+
schema,
3989+
};
3990+
const { node } = createFormComponent(props);
3991+
const checkbox = node.querySelector('input[type="checkbox"]');
3992+
const input = node.querySelector('input[type="text"]');
3993+
expect(formRef.current.reset).to.exist;
3994+
expect(checkbox).to.exist;
3995+
expect(input).to.exist;
3996+
expect(checkbox.checked).to.eq(true);
3997+
expect(input.getAttribute('value')).to.eq('');
3998+
formRef.current.reset();
3999+
expect(checkbox.checked).to.eq(true);
4000+
expect(input.getAttribute('value')).to.eq('');
4001+
Simulate.change(checkbox, { target: { checked: false } });
4002+
Simulate.change(input, { target: { value: 'Changed value' } });
4003+
expect(checkbox.checked).to.eq(false);
4004+
expect(input.getAttribute('value')).to.eq('Changed value');
4005+
formRef.current.reset();
4006+
expect(input.getAttribute('value')).to.eq('');
4007+
expect(checkbox.checked).to.eq(true);
4008+
});
4009+
});
39154010
});
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{
2+
"title": "Widgets",
3+
"type": "object",
4+
"properties": {
5+
"stringFormats": {
6+
"type": "object",
7+
"title": "String formats",
8+
"properties": {
9+
"email": {
10+
"type": "string",
11+
"format": "email"
12+
},
13+
"uri": {
14+
"type": "string",
15+
"format": "uri"
16+
}
17+
}
18+
},
19+
"boolean": {
20+
"type": "object",
21+
"title": "Boolean field",
22+
"properties": {
23+
"default": {
24+
"type": "boolean",
25+
"title": "checkbox (default)",
26+
"description": "This is the checkbox-description",
27+
"default": true
28+
},
29+
"radio": {
30+
"type": "boolean",
31+
"title": "radio buttons",
32+
"description": "This is the radio-description"
33+
},
34+
"select": {
35+
"type": "boolean",
36+
"title": "select box",
37+
"description": "This is the select-description"
38+
}
39+
}
40+
},
41+
"string": {
42+
"type": "object",
43+
"title": "String field",
44+
"properties": {
45+
"default": {
46+
"type": "string",
47+
"title": "text input (default)"
48+
},
49+
"textarea": {
50+
"type": "string",
51+
"title": "textarea"
52+
},
53+
"placeholder": {
54+
"type": "string"
55+
},
56+
"color": {
57+
"type": "string",
58+
"title": "color picker",
59+
"default": "#151ce6"
60+
}
61+
}
62+
},
63+
"secret": {
64+
"type": "string",
65+
"default": "I'm a hidden string."
66+
},
67+
"disabled": {
68+
"type": "string",
69+
"title": "A disabled field",
70+
"default": "I am disabled."
71+
},
72+
"readonly": {
73+
"type": "string",
74+
"title": "A readonly field",
75+
"default": "I am read-only."
76+
},
77+
"readonly2": {
78+
"type": "string",
79+
"title": "Another readonly field",
80+
"default": "I am also read-only.",
81+
"readOnly": true
82+
}
83+
}
84+
}

packages/playground/src/app.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,15 @@ class Playground extends Component {
527527
>
528528
Prog. Validate
529529
</button>
530+
<button
531+
title='Click me to reset the form programmatically.'
532+
className='btn btn-default'
533+
type='button'
534+
onClick={() => this.playGroundForm.current.reset()}
535+
>
536+
Prog. Reset
537+
</button>
538+
<span> </span>
530539
<div style={{ marginTop: '5px' }} />
531540
<CopyLink shareURL={this.state.shareURL} onShare={this.onShare} />
532541
</div>

0 commit comments

Comments
 (0)