Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Prevent duplicate extraErrors when not live validating #3288

Merged
merged 3 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ should change the heading of the (upcoming) version to include a major version b

## @rjsf/core
- Added `ref` definition to `ThemeProps` fixing [#2135](https://github.com/rjsf-team/react-jsonschema-form/issues/2135)
- Updated the `onChange` handler in `Form` to use the new `preventDuplicates` mode of `mergeObjects()` when merging `extraErrors` when live validation is off, fixing [#3169](https://github.com/rjsf-team/react-jsonschema-form/issues/3169)

## @rjsf/utils
- Updated `computedDefaults` (used by `getDefaultFormState`) to skip saving the computed default if it's an empty object unless `includeUndefinedValues` is truthy, fixing [#2150](https://github.com/rjsf-team/react-jsonschema-form/issues/2150) and [#2708](https://github.com/rjsf-team/react-jsonschema-form/issues/2708)
- Expanded the `getDefaultFormState` util's `includeUndefinedValues` prop to accept a boolean or `"excludeObjectChildren"` if it does not want to include undefined values in nested objects
- Updated `mergeObjects` to add new `preventDuplicates` mode when concatenating arrays so that only unique values from the source object array are copied to the destination object array

## Dev / docs / playground
- Removed extraneous leading space on the examples in the validation documentation, fixing [#3282](https://github.com/rjsf-team/react-jsonschema-form/issues/3282)
- Updated the documentation for `mergeObjects()` for the new `preventDuplicates` mode of concatenating arrays
- Updated the documentation for unpkg releases to the correct name fixing the confusion found in [#3262](https://github.com/rjsf-team/react-jsonschema-form/issues/3262)

# 5.0.0-beta.13

Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/utility-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ Recursively merge deeply nested objects.
#### Parameters
- obj1: GenericObjectType - The first object to merge
- obj2: GenericObjectType - The second object to merge
- [concatArrays=false]: boolean - Optional flag that, when true, will cause arrays to be concatenated
- [concatArrays=false]: boolean | "preventDuplicates" - Optional flag that, when true, will cause arrays to be concatenated. Use "preventDuplicates" to merge arrays in a manner that prevents any duplicate entries from being merged.

#### Returns
@returns - A new object that is the merge of the two given objects
Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ Our latest version requires React 16+. You can also install `react-jsonschema-fo
### As a script served from a CDN

```html
<script src="https://unpkg.com/@rjsf/core/dist/react-jsonschema-form.js"></script>
<script src="https://unpkg.com/@rjsf/core/dist/core.cjs.production.min.js"></script>
```

Source maps are available at [this url](https://unpkg.com/@rjsf/core/dist/react-jsonschema-form.js.map).
Source maps are available at [this url](https://unpkg.com/@rjsf/core/dist/core.cjs.production.min.js.map).

> Note: The CDN version **does not** embed `react` or `react-dom`.
> Note: The CDN version **does not** embed `react` or `react-dom`. If you want other distributions (i.e. umd, esm), look [here](https://unpkg.com/@rjsf/core/dist) for all releases

You'll also need to alias the default export property to use the Form component:

Expand Down
4 changes: 2 additions & 2 deletions docs/usage/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ NOTE: The `ajv-i18n` validators implement the `Localizer` interface.

Using a specific locale while including all of `ajv-i18n`:

```tsx
```tsx
import { RJSFSchema } from "@rjsf/utils";
import { customizeValidator } from '@rjsf/validator-ajv8';
import localizer from "ajv-i18n";
Expand All @@ -514,7 +514,7 @@ render((

Using a specific locale minimizing the bundle size

```tsx
```tsx
import { RJSFSchema } from "@rjsf/utils";
import { customizeValidator } from '@rjsf/validator-ajv8';
import spanishLocalizer from "ajv-i18n/localize/es";
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,11 @@ export default class Form<
};
} else if (!noValidate && newErrorSchema) {
const errorSchema = extraErrors
? (mergeObjects(newErrorSchema, extraErrors, true) as ErrorSchema<T>)
? (mergeObjects(
newErrorSchema,
extraErrors,
"preventDuplicates"
) as ErrorSchema<T>)
: newErrorSchema;
state = {
formData: newFormData,
Expand Down
16 changes: 13 additions & 3 deletions packages/utils/src/mergeObjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@ import { GenericObjectType } from "./types";
*
* @param obj1 - The first object to merge
* @param obj2 - The second object to merge
* @param [concatArrays=false] - Optional flag that, when true, will cause arrays to be concatenated
* @param [concatArrays=false] - Optional flag that, when true, will cause arrays to be concatenated. Use
* "preventDuplicates" to merge arrays in a manner that prevents any duplicate entries from being merged.
* @returns - A new object that is the merge of the two given objects
*/
export default function mergeObjects(
obj1: GenericObjectType,
obj2: GenericObjectType,
concatArrays = false
concatArrays: boolean | "preventDuplicates" = false
) {
return Object.keys(obj2).reduce((acc, key) => {
const left = obj1 ? obj1[key] : {},
right = obj2[key];
if (obj1 && key in obj1 && isObject(right)) {
acc[key] = mergeObjects(left, right, concatArrays);
} else if (concatArrays && Array.isArray(left) && Array.isArray(right)) {
acc[key] = left.concat(right);
let toMerge = right;
if (concatArrays === "preventDuplicates") {
toMerge = right.reduce((result, value) => {
if (!left.includes(value)) {
heath-freenome marked this conversation as resolved.
Show resolved Hide resolved
result.push(value);
}
return result;
}, []);
}
acc[key] = left.concat(toMerge);
} else {
acc[key] = right;
}
Expand Down
18 changes: 18 additions & 0 deletions packages/utils/test/mergeObjects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,23 @@ describe("mergeObjects()", () => {
a: { b: [1, 2] },
});
});

it("should not concat duplicate values in arrays when concatArrays is 'preventDuplicates'", () => {
const obj1 = { a: [1] };
const obj2 = { a: [1, 2] };

expect(mergeObjects(obj1, obj2, "preventDuplicates")).toEqual({
a: [1, 2],
});
});

it("should not concat duplicate values in nested arrays when concatArrays is 'preventDuplicates'", () => {
const obj1 = { a: { b: [1] } };
const obj2 = { a: { b: [1, 2] } };

expect(mergeObjects(obj1, obj2, "preventDuplicates")).toEqual({
a: { b: [1, 2] },
});
});
});
});