From f5c98f35b1d80fff48c995734f592ebce04df5a2 Mon Sep 17 00:00:00 2001 From: Abdallah Al-Soqatri Date: Thu, 19 Dec 2024 00:23:27 +0100 Subject: [PATCH 1/2] Fixed issue with assigning values to deeply nested required properties --- CHANGELOG.md | 6 +++ .../utils/src/schema/getDefaultFormState.ts | 13 +++--- .../test/schema/getDefaultFormStateTest.ts | 42 +++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffdce1c64c..fe7c1523b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ should change the heading of the (upcoming) version to include a major version b --> +# 5.24.0 + +## @rjsf/utils + +- Fixed issue with assigning default values to formData with deeply nested required properties, fixing [#4399](https://github.com/rjsf-team/react-jsonschema-form/issues/4399) + # 5.23.2 ## @rjsf/core diff --git a/packages/utils/src/schema/getDefaultFormState.ts b/packages/utils/src/schema/getDefaultFormState.ts index f367b2cbf0..ba0cf7bec7 100644 --- a/packages/utils/src/schema/getDefaultFormState.ts +++ b/packages/utils/src/schema/getDefaultFormState.ts @@ -115,11 +115,11 @@ function maybeAddDefaultToObject( // Or if the schema has a const property defined, then we should always return the computedDefault since it's coming from the const. obj[key] = computedDefault; } else if (emptyObjectFields !== 'skipDefaults') { - if (isObject(computedDefault)) { - // If isParentRequired is undefined, then we are at the root level of the schema so defer to the requiredness of - // the field key itself in the `requiredField` list - const isSelfOrParentRequired = isParentRequired === undefined ? requiredFields.includes(key) : isParentRequired; + // If isParentRequired is undefined, then we are at the root level of the schema so defer to the requiredness of + // the field key itself in the `requiredField` list + const isSelfOrParentRequired = isParentRequired === undefined ? requiredFields.includes(key) : isParentRequired; + if (isObject(computedDefault)) { // If emptyObjectFields 'skipEmptyDefaults' store computedDefault if it's a non-empty object(e.g. not {}) if (emptyObjectFields === 'skipEmptyDefaults') { if (!isEmpty(computedDefault)) { @@ -138,11 +138,12 @@ function maybeAddDefaultToObject( } else if ( // Store computedDefault if it's a defined primitive (e.g., true) and satisfies certain conditions // Condition 1: computedDefault is not undefined - // Condition 2: If emptyObjectFields is 'populateAllDefaults' or 'skipEmptyDefaults) or if the key is a required field + // Condition 2: If emptyObjectFields is 'populateAllDefaults' or 'skipEmptyDefaults) + // Or if isSelfOrParentRequired is 'true' and the key is a required field computedDefault !== undefined && (emptyObjectFields === 'populateAllDefaults' || emptyObjectFields === 'skipEmptyDefaults' || - requiredFields.includes(key)) + (isSelfOrParentRequired && requiredFields.includes(key))) ) { obj[key] = computedDefault; } diff --git a/packages/utils/test/schema/getDefaultFormStateTest.ts b/packages/utils/test/schema/getDefaultFormStateTest.ts index cf3ef4cd6a..6cf5da2979 100644 --- a/packages/utils/test/schema/getDefaultFormStateTest.ts +++ b/packages/utils/test/schema/getDefaultFormStateTest.ts @@ -2284,6 +2284,48 @@ export default function getDefaultFormStateTest(testValidator: TestValidatorType }) ).toEqual({ requiredProperty: 'foo' }); }); + it('test an object with a required property that has a nested optional property which has a nested required property with default', () => { + const schema: RJSFSchema = { + type: 'object', + properties: { + baseRequiredProperty: { + type: 'object', + properties: { + optionalProperty: { + type: 'object', + properties: { + nestedRequiredProperty: { + type: 'string', + default: '', + }, + }, + required: ['nestedRequiredProperty'], + }, + requiredProperty: { + type: 'string', + default: 'foo', + }, + }, + required: ['requiredProperty'], + }, + baseOptionalProperty: { + type: 'string', + default: 'baseOptionalProperty', + }, + }, + required: ['baseRequiredProperty'], + }; + expect( + computeDefaults(testValidator, schema, { + rootSchema: schema, + experimental_defaultFormStateBehavior: { emptyObjectFields: 'populateRequiredDefaults' }, + }) + ).toEqual({ + baseRequiredProperty: { + requiredProperty: 'foo', + }, + }); + }); it('test an object with an optional property that has a nested required property and includeUndefinedValues', () => { const schema: RJSFSchema = { type: 'object', From d1bfd3c3cb20ce4e82fdd63a66b765bae62e2732 Mon Sep 17 00:00:00 2001 From: Heath C <51679588+heath-freenome@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:34:56 -0800 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe7c1523b9..e9604c0798 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ should change the heading of the (upcoming) version to include a major version b --> -# 5.24.0 +# 5.23.3 ## @rjsf/utils