Skip to content

Commit 62f3397

Browse files
Bug: Issue with array schema defaults not applying properly when formData 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 <[email protected]> Co-authored-by: Heath C <[email protected]>
1 parent b1cda9b commit 62f3397

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ should change the heading of the (upcoming) version to include a major version b
1818

1919
# 5.22.4
2020

21+
## @rjsf/utils
22+
23+
- 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).
24+
2125
## Dev / docs / playground
2226

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

2731
## @rjsf/utils
2832

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

3135
# 5.22.2
3236

packages/docs/docs/api-reference/form-props.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ render(
181181
schema={schema}
182182
validator={validator}
183183
experimental_defaultFormStateBehavior={{
184-
arrayMinItems: { populate: 'requiredOnly' },
184+
emptyObjectFields: 'populateRequiredDefaults',
185185
}}
186186
/>,
187187
document.getElementById('app')

packages/utils/src/schema/getDefaultFormState.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,11 +432,14 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
432432
): T | T[] | undefined {
433433
const schema: S = rawSchema;
434434

435-
const neverPopulate = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'never';
436-
const ignoreMinItemsFlagSet = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'requiredOnly';
435+
const arrayMinItemsStateBehavior = experimental_defaultFormStateBehavior?.arrayMinItems ?? {};
436+
const { populate: arrayMinItemsPopulate, mergeExtraDefaults: arrayMergeExtraDefaults } = arrayMinItemsStateBehavior;
437+
438+
const neverPopulate = arrayMinItemsPopulate === 'never';
439+
const ignoreMinItemsFlagSet = arrayMinItemsPopulate === 'requiredOnly';
440+
const isPopulateAll = arrayMinItemsPopulate === 'all' || (!neverPopulate && !ignoreMinItemsFlagSet);
441+
const computeSkipPopulate = arrayMinItemsStateBehavior?.computeSkipPopulate ?? (() => false);
437442
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
438-
const computeSkipPopulate =
439-
experimental_defaultFormStateBehavior?.arrayMinItems?.computeSkipPopulate ?? (() => false);
440443

441444
const emptyDefault = isSkipEmptyDefaults ? undefined : [];
442445

@@ -460,7 +463,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
460463
if (neverPopulate) {
461464
defaults = rawFormData;
462465
} else {
463-
defaults = rawFormData.map((item: T, idx: number) => {
466+
const itemDefaults = rawFormData.map((item: T, idx: number) => {
464467
return computeDefaults<T, S, F>(validator, schemaItem, {
465468
rootSchema,
466469
_recurseList,
@@ -470,6 +473,11 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
470473
required,
471474
});
472475
}) as T[];
476+
477+
// If the populate 'requiredOnly' flag is set then we only merge and include extra defaults if they are required.
478+
// Or if populate 'all' is set we merge and include extra defaults.
479+
const mergeExtraDefaults = ((ignoreMinItemsFlagSet && required) || isPopulateAll) && arrayMergeExtraDefaults;
480+
defaults = mergeDefaultsWithFormData(defaults, itemDefaults, mergeExtraDefaults);
473481
}
474482
}
475483

packages/utils/test/schema/getDefaultFormStateTest.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,49 @@ export default function getDefaultFormStateTest(testValidator: TestValidatorType
644644
},
645645
});
646646
});
647+
it('test an array with defaults with no formData', () => {
648+
const schema: RJSFSchema = {
649+
type: 'array',
650+
minItems: 4,
651+
default: ['Raphael', 'Michaelangelo'],
652+
items: {
653+
type: 'string',
654+
default: 'Unknown',
655+
},
656+
};
657+
658+
expect(
659+
computeDefaults(testValidator, schema, {
660+
rootSchema: schema,
661+
includeUndefinedValues: 'excludeObjectChildren',
662+
})
663+
).toEqual(['Raphael', 'Michaelangelo', 'Unknown', 'Unknown']);
664+
});
665+
it('test an array with defaults with empty array as formData', () => {
666+
const schema: RJSFSchema = {
667+
type: 'array',
668+
minItems: 4,
669+
default: ['Raphael', 'Michaelangelo'],
670+
items: {
671+
type: 'string',
672+
default: 'Unknown',
673+
},
674+
};
675+
676+
expect(
677+
computeDefaults(testValidator, schema, {
678+
rootSchema: schema,
679+
rawFormData: [],
680+
includeUndefinedValues: 'excludeObjectChildren',
681+
experimental_defaultFormStateBehavior: {
682+
arrayMinItems: {
683+
mergeExtraDefaults: true,
684+
populate: 'all',
685+
},
686+
},
687+
})
688+
).toEqual(['Raphael', 'Michaelangelo', 'Unknown', 'Unknown']);
689+
});
647690
it('test computeDefaults handles an invalid property schema', () => {
648691
const schema: RJSFSchema = {
649692
type: 'object',

0 commit comments

Comments
 (0)