Skip to content

Commit 4339d05

Browse files
committed
Merge branch 'main' into fix/issuse-4426
2 parents d196a0c + f5a24b2 commit 4339d05

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

CHANGELOG.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ should change the heading of the (upcoming) version to include a major version b
2424

2525
# 5.23.3
2626

27+
## @rjsf/core
28+
29+
- Fixed issue with schema if/then/else conditions where switching to then/else subschemas did not reflect the actual validation errors in the onChange event, fixing [#4249](https://github.com/rjsf-team/react-jsonschema-form/issues/4249) and improving performance.
30+
2731
## @rjsf/utils
2832

2933
- Fixed issue with formData not updating when dependencies change, fixing [#4325](https://github.com/rjsf-team/react-jsonschema-form/issues/4325)
@@ -195,18 +199,18 @@ should change the heading of the (upcoming) version to include a major version b
195199
## @rjsf/core
196200

197201
- Support allowing raising errors from within a custom Widget [#2718](https://github.com/rjsf-team/react-jsonschema-form/issues/2718)
198-
- Updated `ArrayField`, `BooleanField` and `StringField` to call `optionsList()` with the additional `UiSchema` parameter, fixing [#4215](https://github.com/rjsf-team/react-jsonschema-form/issues/4215) and [#4260](https://github.com/rjsf-team/react-jsonschema-form/issues/4260)
202+
- Updated `ArrayField`, `BooleanField` and `StringField` to call `optionsList()` with the additional `UiSchema` parameter, fixing [#4215](https://github.com/rjsf-team/react-jsonschema-form/issues/4215) and [#4260](https://github.com/rjsf-team/react-jsonschema-form/issues/4260)
199203

200204
## @rjsf/utils
201205

202206
- Updated the `WidgetProps` type to add `es?: ErrorSchema<T>, id?: string` to the params of the `onChange` handler function
203207
- Updated `UIOptionsBaseType` to add the new `enumNames` prop to support an alternate way to provide labels for `enum`s in a schema, fixing [#4215](https://github.com/rjsf-team/react-jsonschema-form/issues/4215)
204-
- Updated `optionsList()` to take an optional `uiSchema` that is used to extract alternate labels for `enum`s or `oneOf`/`anyOf` in a schema, fixing [#4215](https://github.com/rjsf-team/react-jsonschema-form/issues/4215) and [#4260](https://github.com/rjsf-team/react-jsonschema-form/issues/4260)
208+
- Updated `optionsList()` to take an optional `uiSchema` that is used to extract alternate labels for `enum`s or `oneOf`/`anyOf` in a schema, fixing [#4215](https://github.com/rjsf-team/react-jsonschema-form/issues/4215) and [#4260](https://github.com/rjsf-team/react-jsonschema-form/issues/4260)
205209
- NOTE: The generics for `optionsList()` were expanded from `<S extends StrictRJSFSchema = RJSFSchema>` to `<S extends StrictRJSFSchema = RJSFSchema, T = any, F extends FormContextType = any>` to support the `UiSchema`.
206210

207211
## Dev / docs / playground
208212

209-
- Update the `custom-widget-fields.md` to add documentation for how to raise errors from a custom widget or field
213+
- Update the `custom-widget-fields.md` to add documentation for how to raise errors from a custom widget or field
210214

211215
# 5.19.4
212216

packages/core/src/components/Form.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,9 @@ export default class Form<
421421
);
422422
}
423423
const formData: T = schemaUtils.getDefaultFormState(schema, inputFormData) as T;
424-
const _retrievedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);
424+
const _retrievedSchema = this.updateRetrievedSchema(
425+
retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData)
426+
);
425427

426428
const getCurrentErrors = (): ValidationData<T> => {
427429
// If the `props.noValidate` option is set or the schema has changed, we reset the error state.
@@ -475,6 +477,7 @@ export default class Form<
475477
) as ErrorSchema<T>;
476478
}
477479
}
480+
478481
if (props.extraErrors) {
479482
const merged = validationDataMerge({ errorSchema, errors }, props.extraErrors);
480483
errorSchema = merged.errorSchema;
@@ -665,11 +668,13 @@ export default class Form<
665668
*/
666669
onChange = (formData: T | undefined, newErrorSchema?: ErrorSchema<T>, id?: string) => {
667670
const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
668-
const { schemaUtils, schema, retrievedSchema } = this.state;
671+
const { schemaUtils, schema } = this.state;
669672

673+
let retrievedSchema = this.state.retrievedSchema;
670674
if (isObject(formData) || Array.isArray(formData)) {
671-
const newState = this.getStateFromProps(this.props, formData, retrievedSchema);
675+
const newState = this.getStateFromProps(this.props, formData);
672676
formData = newState.formData;
677+
retrievedSchema = newState.retrievedSchema;
673678
}
674679

675680
const mustValidate = !noValidate && liveValidate;
@@ -719,6 +724,20 @@ export default class Form<
719724
this.setState(state as FormState<T, S, F>, () => onChange && onChange({ ...this.state, ...state }, id));
720725
};
721726

727+
/**
728+
* If the retrievedSchema has changed the new retrievedSchema is returned.
729+
* Otherwise, the old retrievedSchema is returned to persist reference.
730+
* - This ensures that AJV retrieves the schema from the cache when it has not changed,
731+
* avoiding the performance cost of recompiling the schema.
732+
*
733+
* @param retrievedSchema The new retrieved schema.
734+
* @returns The new retrieved schema if it has changed, else the old retrieved schema.
735+
*/
736+
private updateRetrievedSchema(retrievedSchema: S) {
737+
const isTheSame = deepEquals(retrievedSchema, this.state?.retrievedSchema);
738+
return isTheSame ? this.state.retrievedSchema : retrievedSchema;
739+
}
740+
722741
/**
723742
* Callback function to handle reset form data.
724743
* - Reset all fields with default values.

packages/core/test/ObjectField.test.jsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,56 @@ describe('ObjectField', () => {
227227
});
228228
});
229229

230+
it('Check schema with if/then/else conditions and activate the then/else subschemas, the onChange event should reflect the actual validation errors', () => {
231+
const schema = {
232+
type: 'object',
233+
_const: 'test',
234+
required: ['checkbox'],
235+
properties: {
236+
checkbox: {
237+
type: 'boolean',
238+
},
239+
},
240+
if: {
241+
required: ['checkbox'],
242+
properties: {
243+
checkbox: {
244+
const: true,
245+
},
246+
},
247+
},
248+
then: {
249+
required: ['text'],
250+
properties: {
251+
text: {
252+
type: 'string',
253+
},
254+
},
255+
},
256+
};
257+
258+
const { node, onChange } = createFormComponent({
259+
schema,
260+
formData: {
261+
checkbox: true,
262+
},
263+
liveValidate: true,
264+
});
265+
266+
// Uncheck the checkbox
267+
fireEvent.click(node.querySelector('input[type=checkbox]'));
268+
269+
sinon.assert.calledWithMatch(
270+
onChange.lastCall,
271+
{
272+
formData: { checkbox: false },
273+
errorSchema: {},
274+
errors: [],
275+
},
276+
'root_checkbox'
277+
);
278+
});
279+
230280
it('Check that when formData changes, the form should re-validate', () => {
231281
const { node, rerender } = createFormComponent({
232282
schema,

0 commit comments

Comments
 (0)