Skip to content

Commit

Permalink
Bug: Issue with array schema defaults not applying properly when form…
Browse files Browse the repository at this point in the history
…Data is an empty array (#4359)

* Fixed issue with array schema defaults not applying properly when formData is an empty array.

* improvement based on feedback

* fixed docs error

---------

Co-authored-by: Abdallah Al-Soqatri <abdallah.al-soqatri@aspentech.com>
Co-authored-by: Heath C <51679588+heath-freenome@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 8, 2024
1 parent b1cda9b commit 62f3397
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 7 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ should change the heading of the (upcoming) version to include a major version b

# 5.22.4

## @rjsf/utils

- Fixed issue with array schema defaults not applying properly when formData is an empty array, fixing [#4335](https://github.com/rjsf-team/react-jsonschema-form/issues/4335).

## Dev / docs / playground

- Fix issue 'Maximum call stack size exceeded' with playground share with large content.
Expand All @@ -26,7 +30,7 @@ should change the heading of the (upcoming) version to include a major version b

## @rjsf/utils

- Fixed deep nested dependencies issue with assigning values to formData, fixing [[#4334](https://github.com/rjsf-team/react-jsonschema-form/issues/4334)]
- Fixed deep nested dependencies issue with assigning values to formData, fixing [#4334](https://github.com/rjsf-team/react-jsonschema-form/issues/4334)

# 5.22.2

Expand Down
2 changes: 1 addition & 1 deletion packages/docs/docs/api-reference/form-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ render(
schema={schema}
validator={validator}
experimental_defaultFormStateBehavior={{
arrayMinItems: { populate: 'requiredOnly' },
emptyObjectFields: 'populateRequiredDefaults',
}}
/>,
document.getElementById('app')
Expand Down
18 changes: 13 additions & 5 deletions packages/utils/src/schema/getDefaultFormState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,14 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
): T | T[] | undefined {
const schema: S = rawSchema;

const neverPopulate = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'never';
const ignoreMinItemsFlagSet = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'requiredOnly';
const arrayMinItemsStateBehavior = experimental_defaultFormStateBehavior?.arrayMinItems ?? {};
const { populate: arrayMinItemsPopulate, mergeExtraDefaults: arrayMergeExtraDefaults } = arrayMinItemsStateBehavior;

const neverPopulate = arrayMinItemsPopulate === 'never';
const ignoreMinItemsFlagSet = arrayMinItemsPopulate === 'requiredOnly';
const isPopulateAll = arrayMinItemsPopulate === 'all' || (!neverPopulate && !ignoreMinItemsFlagSet);
const computeSkipPopulate = arrayMinItemsStateBehavior?.computeSkipPopulate ?? (() => false);
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
const computeSkipPopulate =
experimental_defaultFormStateBehavior?.arrayMinItems?.computeSkipPopulate ?? (() => false);

const emptyDefault = isSkipEmptyDefaults ? undefined : [];

Expand All @@ -460,7 +463,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
if (neverPopulate) {
defaults = rawFormData;
} else {
defaults = rawFormData.map((item: T, idx: number) => {
const itemDefaults = rawFormData.map((item: T, idx: number) => {
return computeDefaults<T, S, F>(validator, schemaItem, {
rootSchema,
_recurseList,
Expand All @@ -470,6 +473,11 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
required,
});
}) as T[];

// If the populate 'requiredOnly' flag is set then we only merge and include extra defaults if they are required.
// Or if populate 'all' is set we merge and include extra defaults.
const mergeExtraDefaults = ((ignoreMinItemsFlagSet && required) || isPopulateAll) && arrayMergeExtraDefaults;
defaults = mergeDefaultsWithFormData(defaults, itemDefaults, mergeExtraDefaults);
}
}

Expand Down
43 changes: 43 additions & 0 deletions packages/utils/test/schema/getDefaultFormStateTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,49 @@ export default function getDefaultFormStateTest(testValidator: TestValidatorType
},
});
});
it('test an array with defaults with no formData', () => {
const schema: RJSFSchema = {
type: 'array',
minItems: 4,
default: ['Raphael', 'Michaelangelo'],
items: {
type: 'string',
default: 'Unknown',
},
};

expect(
computeDefaults(testValidator, schema, {
rootSchema: schema,
includeUndefinedValues: 'excludeObjectChildren',
})
).toEqual(['Raphael', 'Michaelangelo', 'Unknown', 'Unknown']);
});
it('test an array with defaults with empty array as formData', () => {
const schema: RJSFSchema = {
type: 'array',
minItems: 4,
default: ['Raphael', 'Michaelangelo'],
items: {
type: 'string',
default: 'Unknown',
},
};

expect(
computeDefaults(testValidator, schema, {
rootSchema: schema,
rawFormData: [],
includeUndefinedValues: 'excludeObjectChildren',
experimental_defaultFormStateBehavior: {
arrayMinItems: {
mergeExtraDefaults: true,
populate: 'all',
},
},
})
).toEqual(['Raphael', 'Michaelangelo', 'Unknown', 'Unknown']);
});
it('test computeDefaults handles an invalid property schema', () => {
const schema: RJSFSchema = {
type: 'object',
Expand Down

0 comments on commit 62f3397

Please sign in to comment.