Skip to content

Commit

Permalink
fix: Allow formData to be optional everywhere (#3395)
Browse files Browse the repository at this point in the history
Fixes #3305 by ensuring that `formData` can be optional everywhere

There were some types which were requiring `formData` to be required even though it really can be optional everywhere
- In `@rjsf/utils`, updated the `formData` prop in all types where it was required to make it optional
  - Also updated all function arguments where it was required to make `formData` optional
- In `@rjsf/validator-ajv6` and `@rjsf/validator-ajv8`, updated places where `formData` was required as a function parameter to make it optional instead
- In `@rjsf/core`, updated places where `formData` was required as a function parameter to make it optional instead
- In `utility-functions.md`, updated the documentation of optional parameters without default values to ensure they included `| undefined` in the type of the parameter
- In `5.x upgrade guide.md`, updated the note about improved typescript typing in `@rjsf/utils` to indicate that it may require updating typing in the user's implementations
- Updated the `CHANGELOG.md` accordingly
  • Loading branch information
heath-freenome authored Jan 24, 2023
1 parent ff431e4 commit 5555123
Show file tree
Hide file tree
Showing 16 changed files with 104 additions and 66 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ should change the heading of the (upcoming) version to include a major version b
- [#1661](https://github.com/rjsf-team/react-jsonschema-form/issues/1661)
- And probably others
- Updated `ObjectField` to deal with `additionalProperties` with `oneOf`/`anyOf`, fixing [#2538](https://github.com/rjsf-team/react-jsonschema-form/issues/2538)
- Updated `Form`, `MultiSchemaField`, `ObjectField` and `SchemaField` to properly support making `formData` optional, fixing [#3305](https://github.com/rjsf-team/react-jsonschema-form/issues/3305)

## @rjsf/material-ui
- Fix shrinking of `SelectWidget` label only if value is not empty, fixing [#3369](https://github.com/rjsf-team/react-jsonschema-form/issues/3369)
Expand All @@ -41,11 +42,20 @@ should change the heading of the (upcoming) version to include a major version b
- Deprecated `getMatchingOption()` and updated all calls to it in other utility functions to use `getFirstMatchingOption()`
- Updated `stubExistingAdditionalProperties()` to deal with `additionalProperties` with `oneOf`/`anyOf`, fixing [#2538](https://github.com/rjsf-team/react-jsonschema-form/issues/2538)
- Updated `getSchemaType()` to grab the type of the first element of a `oneOf`/`anyOf`, fixing [#1654](https://github.com/rjsf-team/react-jsonschema-form/issues/1654)
- Updated all props or function parameters of the generic type `T` to allow for them to be optionally provided, fixing [#3305](https://github.com/rjsf-team/react-jsonschema-form/issues/3305)
- This was done in both the types file and the actual implementation code

## @rjsf/validator-ajv6
- Updated places where `formData` was required as a function argument to make it optional, fixing [#3305](https://github.com/rjsf-team/react-jsonschema-form/issues/3305)

## @rjsf/validator-ajv8
- Updated places where `formData` was required as a function argument to make it optional, fixing [#3305](https://github.com/rjsf-team/react-jsonschema-form/issues/3305)

## Dev / docs / playground
- Updated the playground to `onFormDataEdited()` to only change the formData in the state if the `JSON.stringify()` of the old and new values are different, partially fixing [#3236](https://github.com/rjsf-team/react-jsonschema-form/issues/3236)
- Updated the playground `npm start` command to always use the `--force` option to avoid issues where changes made to other packages weren't getting picked up due to `vite` caching
- Updated the documentation for `utility-functions` and the `5.x upgrade guide` to add the new utility functions and to document the deprecation of `getMatchingOption()`
- Also updated `utility-functions`, making all optional parameters without a default (as denoted by the syntax `[<parameter>]: <type>`) to add ` | undefined` onto the type to make it clear it supports passing in undefined as a value.

# 5.0.0-beta-17

Expand Down
3 changes: 2 additions & 1 deletion docs/5.x upgrade guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ In version 4, RJSF exported all its types directly from `@rjsf/core`.
In version 5, only the types for the `Form` component and the `withTheme()` HOC are exported directly from `@rjsf/core`.
All the rest of the types for RJSF are now exported from the new `@rjsf/utils` package.

NOTE: The types in `@rjsf/utils` have been improved significantly from those in version 4.
NOTE: The types in `@rjsf/utils` have been improved significantly from those in version 4 and as a result may require you to fix your Typescript typings and add some casts.

Some of the most notable changes are:

- `RJSFSchema` has replaced the use of `JSON7Schema` for future compatibility reasons.
Expand Down
56 changes: 28 additions & 28 deletions docs/api-reference/utility-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ The UI for the field can expand if it has additional properties, is not forced a
#### Parameters
- schema: S - The schema for the field that is being checked
- [uiSchema={}]: UiSchema<T, S, F> - The uiSchema for the field
- [formData]: T - The formData for the field
- [formData]: T | undefined - The formData for the field

#### Returns
- boolean: True if the schema element has additionalProperties, is expandable, and not at the maxProperties limit
Expand Down Expand Up @@ -154,7 +154,7 @@ Using the `schema`, `defaultType` and `options`, extract out the props for the `

#### Parameters
- schema: S - The schema for the field provided by the widget
- [defaultType]: string - The default type, if any, for the field provided by the widget
- [defaultType]: string | undefined - The default type, if any, for the field provided by the widget
- [options={}]: UIOptionsType<T, S, F> - The UI Options for the field provided by the widget
- [autoDefaultStepAny=true]: boolean - Determines whether to auto-default step=any when the type is number and no step
#### Returns
Expand Down Expand Up @@ -311,11 +311,11 @@ When merging defaults and form data, we want to merge in this specific way:
- scalars are overwritten/set by form data

#### Parameters
- defaults: T - The defaults to merge
- formData: T - The form data into which the defaults will be merged
- [defaults]: T | undefined - The defaults to merge
- [formData]: T | undefined - The form data into which the defaults will be merged

#### Returns
- T: The resulting merged form data with defaults
- T | undefined: The resulting merged form data with defaults

### mergeObjects()
Recursively merge deeply nested objects.
Expand Down Expand Up @@ -409,7 +409,7 @@ If the value is an empty string, then the `emptyValue` from the `options` is ret
#### Parameters
- schema: S - The schema to used to determine the value's true type
- [value]: any - The value to convert
- [options]: UIOptionsType<T, S, F> - The UIOptionsType from which to potentially extract the `emptyValue`
- [options]: UIOptionsType<T, S, F> | undefined - The UIOptionsType from which to potentially extract the `emptyValue`

#### Returns
- string | boolean | number | string[] | boolean[] | number[] | undefined: The `value` converted to the proper type
Expand Down Expand Up @@ -498,8 +498,8 @@ Returns the superset of `formData` that includes the given set updated to includ
#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- theSchema: S - The schema for which the default state is desired
- [formData]: T - The current formData, if any, onto which to provide any missing defaults
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [formData]: T | undefined - The current formData, if any, onto which to provide any missing defaults
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
- [includeUndefinedValues=false]: boolean | "excludeObjectChildren" - Optional flag, if true, cause undefined values to be added as defaults. If "excludeObjectChildren", pass `includeUndefinedValues` as false when computing defaults for any nested object properties.

#### Returns
Expand All @@ -512,7 +512,7 @@ Determines whether the combination of `schema` and `uiSchema` properties indicat
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which the display label flag is desired
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to derive potentially displayable information
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s

#### Returns
- boolean: True if the label should be displayed or false if it should not
Expand All @@ -526,7 +526,7 @@ The closest match is determined using the number of matching properties, and mor
#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- rootSchema: S - The root schema, used to primarily to look up `$ref`s
- formData: T | undefined - The current formData, if any, used to figure out a match
- [formData]: T | undefined - The current formData, if any, used to figure out a match
- options: S[] - The list of options to find a matching options from
- [selectedOption=-1]: number - The index of the currently selected option, defaulted to -1 if not specified

Expand All @@ -539,7 +539,7 @@ Always returns the first option if there is nothing that matches.

#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- formData: T | undefined - The current formData, if any, used to figure out a match
- [formData]: T | undefined - The current formData, if any, used to figure out a match
- options: S[] - The list of options to find a matching options from
- rootSchema: S - The root schema, used to primarily to look up `$ref`s

Expand All @@ -552,7 +552,7 @@ Deprecated, use `getFirstMatchingOption()` instead.

#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- formData: T | undefined - The current formData, if any, used to figure out a match
- [formData]: T | undefined - The current formData, if any, used to figure out a match
- options: S[] - The list of options to find a matching options from
- rootSchema: S - The root schema, used to primarily to look up `$ref`s

Expand All @@ -566,7 +566,7 @@ Checks to see if the `schema` and `uiSchema` combination represents an array of
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which check for array of files flag is desired
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to check the widget
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s

#### Returns
- boolean: True if schema/uiSchema contains an array of files, otherwise false
Expand All @@ -577,7 +577,7 @@ Checks to see if the `schema` combination represents a multi-select
#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which check for a multi-select flag is desired
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s

#### Returns
- boolean: True if schema contains a multi-select, otherwise false
Expand All @@ -588,7 +588,7 @@ Checks to see if the `schema` combination represents a select
#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- theSchema: S - The schema for which check for a select flag is desired
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s

#### Returns
- boolean: True if schema contains a select, otherwise false
Expand All @@ -600,7 +600,7 @@ If no `additionalErrorSchema` is passed, then `validationData` is returned.
#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used to convert an ErrorSchema to a list of errors
- validationData: ValidationData<T> - The current `ValidationData` into which to merge the additional errors
- [additionalErrorSchema]: ErrorSchema<T> - The additional set of errors in an `ErrorSchema`
- [additionalErrorSchema]: ErrorSchema<T> | undefined - The additional set of errors in an `ErrorSchema`

#### Returns
- ValidationData<T>: The `validationData` with the additional errors from `additionalErrorSchema` merged into it, if provided.
Expand All @@ -614,7 +614,7 @@ potentially recursive resolution.
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
- schema: S - The schema for which retrieving a schema is desired
- [rootSchema={}]: S - The root schema that will be forwarded to all the APIs
- [rawFormData]: T - The current formData, if any, to assist retrieving a schema
- [rawFormData]: T | undefined - The current formData, if any, to assist retrieving a schema

#### Returns
- RJSFSchema: The schema having its conditions, additional properties, references and dependencies resolved
Expand All @@ -628,8 +628,8 @@ Also, any properties in the old schema that are non-existent in the new schema a
#### Parameters
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- rootSchema: S - The root JSON schema of the entire form
- [newSchema]: S - The new schema for which the data is being sanitized
- [oldSchema]: S - The old schema from which the data originated
- [newSchema]: S | undefined - The new schema for which the data is being sanitized
- [oldSchema]: S | undefined - The old schema from which the data originated
- [data={}]: any - The form data associated with the schema, defaulting to an empty object when undefined

#### Returns
Expand All @@ -642,8 +642,8 @@ Generates an `IdSchema` object for the `schema`, recursively
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which the `IdSchema` is desired
- [id]: string | null - The base id for the schema
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [formData]: T - The current formData, if any, to assist retrieving a schema
- [rootSchema]: S | undefined- The root schema, used to primarily to look up `$ref`s
- [formData]: T | undefined - The current formData, if any, to assist retrieving a schema
- [idPrefix='root']: string - The prefix to use for the id
- [idSeparator='_']: string - The separator to use for the path segments in the id

Expand All @@ -657,8 +657,8 @@ Generates an `PathSchema` object for the `schema`, recursively
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which the `PathSchema` is desired
- [name='']: string - The base name for the schema
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
- [formData]: T - The current formData, if any, to assist retrieving a schema
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
- [formData]: T | undefined - The current formData, if any, to assist retrieving a schema

#### Returns
- PathSchema<T> - The `PathSchema` object for the `schema`
Expand All @@ -684,7 +684,7 @@ Use this class to add, replace or clear errors in an error schema by using eithe
Once you are done building the `ErrorSchema`, you can get the result and/or reset all the errors back to an initial set and start again.

#### Parameters
- [initialSchema]: ErrorSchema<T> - The optional set of initial errors, that will be cloned into the class
- [initialSchema]: ErrorSchema<T> | undefined - The optional set of initial errors, that will be cloned into the class

#### Returns
- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class
Expand All @@ -709,7 +709,7 @@ const errorSchema: ErrorSchema = builder.ErrorSchema;
Resets all errors in the `ErrorSchemaBuilder` back to the `initialSchema` if provided, otherwise an empty set.

#### Parameters
- [initialSchema]: ErrorSchema<T> - The optional set of initial errors, that will be cloned into the class
- [initialSchema]: ErrorSchema<T> | undefined - The optional set of initial errors, that will be cloned into the class

#### Returns
- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class
Expand All @@ -720,7 +720,7 @@ For more information about how to specify the path see the [eslint lodash plugin

#### Parameters
- errorOrList: string | string[] - The error or list of errors to add into the `ErrorSchema`
- [pathOfError]: string | string[] - The optional path into the `ErrorSchema` at which to add the error(s)
- [pathOfError]: string | string[] | undefined - The optional path into the `ErrorSchema` at which to add the error(s)

#### Returns
- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class
Expand All @@ -731,7 +731,7 @@ For more information about how to specify the path see the [eslint lodash plugin

#### Parameters
- errorOrList: string | string[] - The error or list of errors to add into the `ErrorSchema`
- [pathOfError]: string | string[] - The optional path into the `ErrorSchema` at which to add the error(s)
- [pathOfError]: string | string[] | undefined - The optional path into the `ErrorSchema` at which to add the error(s)

#### Returns
- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class
Expand All @@ -741,7 +741,7 @@ Clears the error(s) in the `ErrorSchema` at either the root level or the locatio
For more information about how to specify the path see the [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md).

#### Parameters
- [pathOfError]: string | string[] - The optional path into the `ErrorSchema` at which to add the error(s)
- [pathOfError]: string | string[] | undefined - The optional path into the `ErrorSchema` at which to add the error(s)

#### Returns
- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class
19 changes: 13 additions & 6 deletions packages/core/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export interface FormState<
/** The schemaUtils implementation used by the `Form`, created from the `validator` and the `schema` */
schemaUtils: SchemaUtilsType<T, S, F>;
/** The current data for the form, computed from the `formData` prop and the changes made by the user */
formData: T;
formData?: T;
/** Flag indicating whether the form is in edit mode, true when `formData` is passed to the form, otherwise false */
edit: boolean;
/** The current list of errors for the form, includes `extraErrors` */
Expand Down Expand Up @@ -405,7 +405,7 @@ export default class Form<
* @param altSchemaUtils - The alternate schemaUtils to use for validation
*/
validate(
formData: T,
formData: T | undefined,
schema = this.props.schema,
altSchemaUtils?: SchemaUtilsType<T, S, F>
): ValidationData<T> {
Expand Down Expand Up @@ -455,7 +455,10 @@ export default class Form<
* @param formData - The data for the `Form`
* @param fields - The fields to keep while filtering
*/
getUsedFormData = (formData: T, fields: string[][]): T => {
getUsedFormData = (
formData: T | undefined,
fields: string[][]
): T | undefined => {
// For the case of a single input form
if (fields.length === 0 && typeof formData !== "object") {
return formData;
Expand All @@ -476,9 +479,9 @@ export default class Form<
/** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
*
* @param pathSchema - The `PathSchema` object for the form
* @param formData - The form data to use while checking for empty objects/arrays
* @param [formData] - The form data to use while checking for empty objects/arrays
*/
getFieldNames = (pathSchema: PathSchema<T>, formData: T): string[][] => {
getFieldNames = (pathSchema: PathSchema<T>, formData?: T): string[][] => {
const getAllPaths = (
_obj: GenericObjectType,
acc: string[][] = [],
Expand Down Expand Up @@ -524,7 +527,11 @@ export default class Form<
* @param newErrorSchema - The new `ErrorSchema` based on the field change
* @param id - The id of the field that caused the change
*/
onChange = (formData: T, newErrorSchema?: ErrorSchema<T>, id?: string) => {
onChange = (
formData: T | undefined,
newErrorSchema?: ErrorSchema<T>,
id?: string
) => {
const {
extraErrors,
omitExtraData,
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/components/fields/MultiSchemaField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ class AnyOfField<
* @param options - The list of options to choose from
* @return - The index of the `option` that best matches the `formData`
*/
getMatchingOption(selectedOption: number, formData: T, options: S[]) {
getMatchingOption(
selectedOption: number,
formData: T | undefined,
options: S[]
) {
const { schemaUtils } = this.props.registry;

const option = schemaUtils.getClosestMatchingOption(
Expand Down
Loading

0 comments on commit 5555123

Please sign in to comment.