diff --git a/CHANGELOG.md b/CHANGELOG.md index f129418864..263f735b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ should change the heading of the (upcoming) version to include a major version b ## @rjsf/utils +- Fixed issue with default value not being prefilled when object with if/then is nested inside another object, fixing [#4222](https://github.com/rjsf-team/react-jsonschema-form/issues/4222) - Fixed issue with schema array with nested dependent fixed-length, fixing [#3754](https://github.com/rjsf-team/react-jsonschema-form/issues/3754) diff --git a/packages/utils/src/schema/getDefaultFormState.ts b/packages/utils/src/schema/getDefaultFormState.ts index 6de034230e..733b0689ce 100644 --- a/packages/utils/src/schema/getDefaultFormState.ts +++ b/packages/utils/src/schema/getDefaultFormState.ts @@ -8,6 +8,7 @@ import { CONST_KEY, DEFAULT_KEY, DEPENDENCIES_KEY, + IF_KEY, ONE_OF_KEY, PROPERTIES_KEY, REF_KEY, @@ -478,12 +479,16 @@ export function getObjectDefaults(validator, schema, rootSchema, formData, experimental_customMergeAllOf) - : schema; + // Retrieve the schema: + // - If schema contains `allOf` AND `experimental_defaultFormStateBehavior.allOf` is set to `populateDefaults` + // - OR if schema contains an 'if' AND `emptyObjectFields` is not set to `skipEmptyDefaults` + // This ensures we compute defaults correctly for schemas with these keywords. + const shouldRetrieveSchema = + (experimental_defaultFormStateBehavior?.allOf === 'populateDefaults' && ALL_OF_KEY in schema) || + (experimental_defaultFormStateBehavior?.emptyObjectFields !== 'skipEmptyDefaults' && IF_KEY in schema); + const retrievedSchema = shouldRetrieveSchema + ? retrieveSchema(validator, schema, rootSchema, formData, experimental_customMergeAllOf) + : schema; const parentConst = retrievedSchema[CONST_KEY]; const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce( (acc: GenericObjectType, key: string) => { diff --git a/packages/utils/test/schema/getDefaultFormStateTest.ts b/packages/utils/test/schema/getDefaultFormStateTest.ts index fbdbafa595..11fd6c0d7d 100644 --- a/packages/utils/test/schema/getDefaultFormStateTest.ts +++ b/packages/utils/test/schema/getDefaultFormStateTest.ts @@ -1641,6 +1641,83 @@ export default function getDefaultFormStateTest(testValidator: TestValidatorType ).toEqual(expected); }); }); + + describe('an nested object with if/then condition', () => { + const schema: RJSFSchema = { + type: 'object', + properties: { + wrappingObject: { + type: 'object', + properties: { + checkbox: { + type: 'boolean', + }, + }, + if: { + properties: { + checkbox: { + const: true, + }, + }, + required: ['checkbox'], + }, + then: { + properties: { + foo: { + type: 'string', + default: 'foo value', + }, + }, + required: ['foo'], + }, + }, + }, + }; + const rawFormData = { + wrappingObject: { + checkbox: true, + }, + }; + const expected = { + wrappingObject: { + checkbox: true, + foo: 'foo value', + }, + }; + test('getDefaultFormState', () => { + expect(getDefaultFormState(testValidator, schema, rawFormData, schema)).toEqual(expected); + }); + + test('computeDefaults', () => { + expect( + computeDefaults(testValidator, schema, { + rootSchema: schema, + rawFormData, + shouldMergeDefaultsIntoFormData: true, + }), + ).toEqual(expected); + }); + + test('getDefaultBasedOnSchemaType', () => { + expect( + getDefaultBasedOnSchemaType(testValidator, schema, { + rootSchema: schema, + rawFormData, + shouldMergeDefaultsIntoFormData: true, + }), + ).toEqual(expected); + }); + + test('getObjectDefaults', () => { + expect( + getObjectDefaults(testValidator, schema, { + rootSchema: schema, + rawFormData, + shouldMergeDefaultsIntoFormData: true, + }), + ).toEqual(expected); + }); + }); }); describe('array schemas', () => {