Skip to content

Commit

Permalink
Shows hidden property errors to the form and scroll to it
Browse files Browse the repository at this point in the history
Fixes: #2217
  • Loading branch information
krissvaa committed Oct 31, 2024
1 parent 1d25d64 commit 2248e82
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
19 changes: 15 additions & 4 deletions packages/ts/react-crud/src/autoform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
type ReactElement,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { AutoFormField, type AutoFormFieldProps, type FieldOptions } from './autoform-field.js';
Expand Down Expand Up @@ -278,6 +279,7 @@ export function AutoForm<M extends AbstractModel>({
const form = useForm(model, {
onSubmit: async (formItem) => service.save(formItem),
});
const formErrorRef = useRef<HTMLDivElement>(null);
const [formError, setFormError] = useState<JSX.Element | string>('');
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const modelInfo = useMemo(() => new ModelInfo(model, itemIdProperty), [model]);
Expand All @@ -294,21 +296,30 @@ export function AutoForm<M extends AbstractModel>({
}
}, [item]);

useEffect(() => {
formErrorRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' });
}, [formError]);

function handleSubmitError(error: unknown) {
if (error instanceof ValidationError) {
const nonPropertyErrorMessages = error.errors
.filter((validationError) => !validationError.property)
.map((validationError) => validationError.validatorMessage ?? validationError.message);
.filter((validationError) => !validationError.property || typeof validationError.property === 'string')
.map((validationError) => {
const property = typeof validationError.property === 'string' ? `${validationError.property}: ` : '';
return `${property}${
validationError.validatorMessage ? validationError.validatorMessage : validationError.message
}`;
});
if (nonPropertyErrorMessages.length > 0) {
setFormError(
<>
<div ref={formErrorRef}>
Validation errors:
<ul>
{nonPropertyErrorMessages.map((message, index) => (
<li key={index}>{message}</li>
))}
</ul>
</>,
</div>,
);
}
} else if (error instanceof EndpointError) {
Expand Down
23 changes: 23 additions & 0 deletions packages/ts/react-crud/test/autoform.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,29 @@ describe('@vaadin/hilla-react-crud', () => {
expect(result.queryByText('just a message')).to.not.be.null;
});

it('shows error for whole form has string property', async () => {
const service: CrudService<Person> & HasTestInfo = createService<Person>(personData);
const person = await getItem(service, 1);
// eslint-disable-next-line @typescript-eslint/require-await
service.save = async (_item: Person): Promise<Person | undefined> => {
const valueError: ValueError = {
property: 'myProp',
message: 'message',
value: person,
validator: { message: 'message', validate: () => false },
validatorMessage: 'foobar',
};
throw new ValidationError([valueError]);
};

const result = render(<AutoForm service={service} model={PersonModel} item={person} />);
const form = await FormController.init(user, result.container);
await form.typeInField('First name', 'J'); // to enable the submit button
await form.submit();
expect(result.queryByText('message')).to.be.null;
expect(result.queryByText('myProp: foobar')).to.not.be.null;
});

it('shows a predefined error message when the service returns no entity after saving', async () => {
const service: CrudService<Person> & HasTestInfo = createService<Person>(personData);
service.save = async (item: Person): Promise<Person | undefined> => Promise.resolve(undefined);
Expand Down

0 comments on commit 2248e82

Please sign in to comment.