diff --git a/examples/react/next-server-actions/src/app/action.ts b/examples/react/next-server-actions/src/app/action.ts index 8ffa3fc02..03154ec75 100644 --- a/examples/react/next-server-actions/src/app/action.ts +++ b/examples/react/next-server-actions/src/app/action.ts @@ -9,9 +9,13 @@ import { formOpts } from './shared-code' const serverValidate = createServerValidate({ ...formOpts, onServerValidate: ({ value }) => { - if (value.age < 12) { - return 'Server validation: You must be at least 12 to sign up' - } + if (value.age < 12) + return { + fields: { + age: 'Server validation: You must be at least 12 to sign up', + }, + form: 'Form level Error: Age must be at least 12', + } }, }) diff --git a/examples/react/next-server-actions/src/app/client-component.tsx b/examples/react/next-server-actions/src/app/client-component.tsx index b7e62909c..a7104e555 100644 --- a/examples/react/next-server-actions/src/app/client-component.tsx +++ b/examples/react/next-server-actions/src/app/client-component.tsx @@ -3,7 +3,6 @@ import { useActionState } from 'react' import { mergeForm, useForm, useTransform } from '@tanstack/react-form' import { initialFormState } from '@tanstack/react-form/nextjs' -import { useStore } from '@tanstack/react-store' import someAction from './action' import { formOpts } from './shared-code' @@ -18,14 +17,8 @@ export const ClientComp = () => { ), }) - const formErrors = useStore(form.store, (formState) => formState.errors) - return (
form.handleSubmit()}> - {formErrors.map((error) => ( -

{error}

- ))} - + | undefined + + if (!serverErrorMap) return state + + batch(() => { + void (Object.values(this.fieldInfo) as FieldInfo[]).forEach( + (field) => { + const fieldInstance = field.instance + + if (!fieldInstance) return + + if (fieldInstance.name in serverErrorMap) { + fieldInstance.setMeta((prev) => ({ + ...prev, + errorMap: { + ...prev.errorMap, + onServer: serverErrorMap[fieldInstance.name], + }, + })) + fieldInstance.mount() + } + + this.validateField(fieldInstance.name, 'server') + }, + ) + }) } return state @@ -1503,6 +1532,20 @@ export class FormApi< }, })) } + + /** + * when we have an error for onServer in the state, we want + * to clear the error as soon as the user changes the value in the field + */ + if (cause !== 'server') { + this.baseStore.setState((prev) => ({ + ...prev, + errorMap: { + ...prev.errorMap, + onServer: undefined, + }, + })) + } }) return { hasErrored, fieldsErrorMap: currentValidationErrorMap } @@ -1925,6 +1968,7 @@ export class FormApi< // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition ...prev?.errorMap, onMount: undefined, + onServer: undefined, }, })) } diff --git a/packages/react-form/src/nextjs/createServerValidate.ts b/packages/react-form/src/nextjs/createServerValidate.ts index adaa4de1f..fc1bdaaae 100644 --- a/packages/react-form/src/nextjs/createServerValidate.ts +++ b/packages/react-form/src/nextjs/createServerValidate.ts @@ -96,20 +96,41 @@ export const createServerValidate = validationSource: 'form', })) as UnwrapFormAsyncValidateOrFn | undefined + console.log('ON SERVER ERROR', onServerError) + if (!onServerError) return values - const onServerErrorVal = ( - isGlobalFormValidationError(onServerError) - ? onServerError.form - : onServerError - ) as UnwrapFormAsyncValidateOrFn + let onServerErrorVal = undefined + let onServerErrorValFields = undefined + + if (isGlobalFormValidationError(onServerError)) { + onServerErrorVal = + onServerError.form as UnwrapFormAsyncValidateOrFn + onServerErrorValFields = + onServerError.fields as UnwrapFormAsyncValidateOrFn + } else { + onServerErrorVal = onServerError as UnwrapFormAsyncValidateOrFn + } + + // Extract string values from errors if they're in object format + const errorsArray = onServerErrorVal + ? Array.isArray(onServerErrorVal) + ? onServerErrorVal.map((err) => + typeof err === 'object' ? Object.values(err)[0] : err, + ) + : [ + typeof onServerErrorVal === 'object' + ? Object.values(onServerErrorVal)[0] + : onServerErrorVal, + ] + : [] const formState: ServerFormState = { errorMap: { - onServer: onServerError, + onServer: onServerErrorValFields, }, values, - errors: onServerErrorVal ? [onServerErrorVal] : [], + errors: errorsArray, } throw new ServerValidateError({