From 815767be5f321f48300925f0dff9f834380d7e88 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Mon, 12 Apr 2021 09:32:34 +0200
Subject: [PATCH] Fix array input validation
---
.../src/input/ArrayInput.spec.tsx | 55 ++++++++++++++++++-
.../ra-ui-materialui/src/input/ArrayInput.tsx | 32 +++++++----
2 files changed, 74 insertions(+), 13 deletions(-)
diff --git a/packages/ra-ui-materialui/src/input/ArrayInput.spec.tsx b/packages/ra-ui-materialui/src/input/ArrayInput.spec.tsx
index f3a01393ea4..9258eb7ab5a 100644
--- a/packages/ra-ui-materialui/src/input/ArrayInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/ArrayInput.spec.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { render } from '@testing-library/react';
+import { fireEvent, render, waitFor } from '@testing-library/react';
import { Form } from 'react-final-form';
import arrayMutators from 'final-form-arrays';
@@ -7,6 +7,7 @@ import ArrayInput from './ArrayInput';
import NumberInput from './NumberInput';
import TextInput from './TextInput';
import SimpleFormIterator from '../form/SimpleFormIterator';
+import { minLength, required } from 'ra-core';
describe('', () => {
const onSubmit = jest.fn();
@@ -126,4 +127,56 @@ describe('', () => {
)
).toEqual(['bar', 'baz']);
});
+
+ it('should apply validation to both itself and its inner inputs', async () => {
+ const { getByText, getAllByLabelText, queryByText } = render(
+ (
+
+ )}
+ />
+ );
+
+ fireEvent.click(getByText('ra.action.add'));
+ expect(queryByText('array_min_length')).not.toBeNull();
+ fireEvent.click(getByText('ra.action.add'));
+ const firstId = getAllByLabelText('resources.bar.fields.id *')[0];
+ fireEvent.change(firstId, {
+ target: { value: 'aaa' },
+ });
+ fireEvent.change(firstId, {
+ target: { value: '' },
+ });
+ fireEvent.blur(firstId);
+ const firstFoo = getAllByLabelText('resources.bar.fields.foo *')[0];
+ fireEvent.change(firstFoo, {
+ target: { value: 'aaa' },
+ });
+ fireEvent.change(firstFoo, {
+ target: { value: '' },
+ });
+ fireEvent.blur(firstFoo);
+ expect(queryByText('array_min_length')).toBeNull();
+ await waitFor(() => {
+ expect(queryByText('id_required')).not.toBeNull();
+ expect(queryByText('foo_required')).not.toBeNull();
+ });
+ });
});
diff --git a/packages/ra-ui-materialui/src/input/ArrayInput.tsx b/packages/ra-ui-materialui/src/input/ArrayInput.tsx
index 0e63fcdca84..0fa7acf073b 100644
--- a/packages/ra-ui-materialui/src/input/ArrayInput.tsx
+++ b/packages/ra-ui-materialui/src/input/ArrayInput.tsx
@@ -96,20 +96,21 @@ const ArrayInput: FC = ({
);
}
- const { error, submitError, touched } = fieldProps.meta;
+ const { error, submitError, touched, dirty } = fieldProps.meta;
+ const arrayInputError = getArrayInputError(error || submitError);
return (
= ({
isRequired={isRequired(validate)}
/>
- {!!(touched && (error || submitError)) || helperText ? (
-
-
-
- ) : null}
{cloneElement(Children.only(children), {
...fieldProps,
record,
@@ -136,6 +128,15 @@ const ArrayInput: FC = ({
margin,
disabled,
})}
+ {!!((touched || dirty) && arrayInputError) || helperText ? (
+
+
+
+ ) : null}
);
};
@@ -163,6 +164,13 @@ ArrayInput.defaultProps = {
fullWidth: true,
};
+export const getArrayInputError = error => {
+ if (Array.isArray(error)) {
+ return undefined;
+ }
+ return error;
+};
+
export interface ArrayInputProps extends InputProps {
children: ReactElement;
disabled?: boolean;