Skip to content

Commit baffbf1

Browse files
MarekBodingerBAMarekBodingerheath-freenome
authored
Skip populate function proposal in Experimental_ArrayMinItems (#4121)
* skip populate draft * Added a new `computeSkipPopulate` option in `arrayMinItems`, allowing custom logic to skip populating arrays with default values * Add example in documentation of computeSkipPopulate * Update packages/docs/docs/api-reference/form-props.md Co-authored-by: Heath C <[email protected]> * Update packages/utils/src/types.ts Co-authored-by: Heath C <[email protected]> * Update packages/docs/docs/api-reference/form-props.md Co-authored-by: Heath C <[email protected]> --------- Co-authored-by: Marek Bodinger <[email protected]> Co-authored-by: Heath C <[email protected]>
1 parent bb2093d commit baffbf1

File tree

5 files changed

+108
-0
lines changed

5 files changed

+108
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ should change the heading of the (upcoming) version to include a major version b
2525
## @rjsf/utils
2626

2727
- Added a new `skipEmptyDefault` option in `emptyObjectFields`, fixing [#3880](https://github.com/rjsf-team/react-jsonschema-form/issues/3880)
28+
- Added a new `computeSkipPopulate` option in `arrayMinItems`, allowing custom logic to skip populating arrays with default values, implementing [#4121](https://github.com/rjsf-team/react-jsonschema-form/pull/4121).
2829
- Fixed bug where the string `"\</strong>"` would get printed next to filenames when uploading files, and restored intended bolding of filenames fixing [#4120](https://github.com/rjsf-team/react-jsonschema-form/issues/4120).
2930

3031
## Dev / docs / playground

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,70 @@ Optional enumerated flag controlling how array minItems are populated, defaultin
8484
| `requiredOnly` | Ignore `minItems` on a field when calculating defaults unless the field is required. |
8585
| `never` | Ignore `minItems` on a field when calculating defaults for required and non-required. Value will set only if defined `default` and from `formData` |
8686

87+
#### `arrayMinItems.computeSkipPopulate`
88+
89+
The signature and documentation for this property is as follow:
90+
91+
##### computeSkipPopulate <T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
92+
93+
A function that determines whether to skip populating the array with default values based on the provided validator, schema, and root schema.
94+
If the function returns `true`, the array will not be populated with default values.
95+
If the function returns `false`, the array will be populated with default values according to the `populate` option.
96+
97+
###### Parameters
98+
99+
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that is used to detect valid schema conditions
100+
- schema: S - The schema for which resolving a condition is desired
101+
- [rootSchema]: S - The root schema that will be forwarded to all the APIs
102+
103+
###### Returns
104+
105+
- boolean: A boolean indicating whether to skip populating the array with default values.
106+
107+
108+
##### Example
109+
110+
```tsx
111+
import { RJSFSchema } from '@rjsf/utils';
112+
import validator from '@rjsf/validator-ajv8';
113+
114+
const schema: RJSFSchema = {
115+
type: 'object',
116+
properties: {
117+
stringArray: {
118+
type: 'array',
119+
items: { type: 'string' },
120+
minItems: 1,
121+
},
122+
numberArray: {
123+
type: 'array',
124+
items: { type: 'number' },
125+
minItems: 1,
126+
},
127+
},
128+
required: ['stringArray', 'numberArray'],
129+
};
130+
131+
const computeSkipPopulateNumberArrays = (validator, schema, rootSchema) =>
132+
// These conditions are needed to narrow down the type of the schema.items
133+
!Array.isArray(schema?.items) &&
134+
typeof schema?.items !== 'boolean' &&
135+
schema?.items?.type === 'number',
136+
137+
render(
138+
<Form
139+
schema={schema}
140+
validator={validator}
141+
experimental_defaultFormStateBehavior={{
142+
arrayMinItems: {
143+
computeSkipPopulate: computeSkipPopulateNumberArrays,
144+
},
145+
}}
146+
/>,
147+
document.getElementById('app')
148+
);
149+
```
150+
87151
#### `arrayMinItems.mergeExtraDefaults`
88152

89153
Optional boolean flag, defaulting to `false` when not specified.

packages/utils/src/schema/getDefaultFormState.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
350350
const neverPopulate = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'never';
351351
const ignoreMinItemsFlagSet = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'requiredOnly';
352352
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
353+
const computeSkipPopulate =
354+
experimental_defaultFormStateBehavior?.arrayMinItems?.computeSkipPopulate ?? (() => false);
353355

354356
const emptyDefault = isSkipEmptyDefaults ? undefined : [];
355357

@@ -399,6 +401,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
399401
if (
400402
!schema.minItems ||
401403
isMultiSelect<T, S, F>(validator, schema, rootSchema) ||
404+
computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
402405
schema.minItems <= defaultsLength
403406
) {
404407
return defaults ? defaults : emptyDefault;

packages/utils/src/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ export type Experimental_ArrayMinItems = {
4141
* - `never`: Ignore `minItems` on a field even the field is required.
4242
*/
4343
populate?: 'all' | 'requiredOnly' | 'never';
44+
/** A function that determines whether to skip populating the array with default values based on the provided validator,
45+
* schema, and root schema.
46+
* If the function returns true, the array will not be populated with default values.
47+
* If the function returns false, the array will be populated with default values according to the `populate` option.
48+
* @param validator - An implementation of the `ValidatorType` interface that is used to detect valid schema conditions
49+
* @param schema - The schema for which resolving a condition is desired
50+
* @param [rootSchema] - The root schema that will be forwarded to all the APIs
51+
* @returns A boolean indicating whether to skip populating the array with default values.
52+
*/
53+
computeSkipPopulate?: <T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
54+
validator: ValidatorType<T, S, F>,
55+
schema: S,
56+
rootSchema?: S
57+
) => boolean;
4458
/** When `formData` is provided and does not contain `minItems` worth of data, this flag (`false` by default) controls
4559
* whether the extra data provided by the defaults is appended onto the existing `formData` items to ensure the
4660
* `minItems` condition is met. When false (legacy behavior), only the `formData` provided is merged into the default

packages/utils/test/schema/getDefaultFormStateTest.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2872,5 +2872,31 @@ export default function getDefaultFormStateTest(testValidator: TestValidatorType
28722872
})
28732873
).toEqual({ requiredArray: ['raw0', 'default0'] });
28742874
});
2875+
it('should not populate defaults for array items when computeSkipPopulate returns true', () => {
2876+
const schema: RJSFSchema = {
2877+
type: 'object',
2878+
properties: {
2879+
stringArray: {
2880+
type: 'array',
2881+
items: { type: 'string' },
2882+
minItems: 1,
2883+
},
2884+
numberArray: {
2885+
type: 'array',
2886+
items: { type: 'number' },
2887+
minItems: 1,
2888+
},
2889+
},
2890+
required: ['stringArray', 'numberArray'],
2891+
};
2892+
expect(
2893+
getDefaultFormState(testValidator, schema, {}, schema, false, {
2894+
arrayMinItems: {
2895+
computeSkipPopulate: (_, schema) =>
2896+
!Array.isArray(schema?.items) && typeof schema?.items !== 'boolean' && schema?.items?.type === 'number',
2897+
},
2898+
})
2899+
).toEqual({ stringArray: [undefined], numberArray: [] });
2900+
});
28752901
});
28762902
}

0 commit comments

Comments
 (0)