conform icon indicating copy to clipboard operation
conform copied to clipboard

How to add validation errors manually?

Open stabildev opened this issue 1 year ago • 6 comments

Describe the bug and the expected behavior

I am biting my teeth out with this.

Looking for a way to add validation errors manually like fields.email.errors.push("Invalid email")

Also tried submission.reply in onSubmit, to no effect:

const [form, fields] = useForm<CreateUserInput>({
    shouldValidate: "onSubmit",
    shouldRevalidate: "onInput",
    onValidate: ({ formData }) => parseWithZod(formData, { schema: createUserSchema }),
    onSubmit: (e, { submission }) => {
      e.preventDefault();
      if (submission?.status !== "success") return;
      try {
        await createUser(submission.value);
      } catch (e) {
        return { ...submission, errors: { email: ["Invalid email"] } }
    },
  });

I am not using server actions.

Conform version

1.1.5

Steps to Reproduce the Bug or Issue

const [form, fields] = useForm<CreateUserInput>({
    shouldValidate: "onSubmit",
    shouldRevalidate: "onInput",
    onValidate: ({ formData }) => parseWithZod(formData, { schema: createUserSchema }),
    onSubmit: (e, { submission }) => {
      e.preventDefault();
      if (submission?.status !== "success") return;
      try {
        await createUser(submission.value);
      } catch (e) {
        return { ...submission, errors: { email: ["Invalid email"] } }
    },
  });

What browsers are you seeing the problem on?

No response

Screenshots or Videos

No response

Additional context

No response

stabildev avatar Oct 30 '24 21:10 stabildev

@stabildev ¿are you using nextjs?

juanmarin-co avatar Oct 31 '24 02:10 juanmarin-co

@stabildev ¿are you using nextjs?

Yes

stabildev avatar Oct 31 '24 09:10 stabildev

The way you pass errors from the backend to the form, is trough lastResult property, which you're not using.

Try something like:

action.ts file

"use server";

import { parseWithZod } from "@conform-to/zod";
import { verifyOtpSchema } from "./schema";

export async function myServerAction(_: unknown, formData: FormData) {
  const submission = parseWithZod(formData, {
    schema: verifyOtpSchema,
  });

  if (submission.status !== "success") {
    return submission.reply();
  }

  return submission.reply({
      fieldErrors: {
        name: ["my custom error"],
      },
    });
}

IMPORTANT!

Don't call the server action in the onSubmit function manually, instead use useActionState and pass the action property to the form. It's the most ergonomic way, and handles lastResult for you

form.tsx

"use client";

import { getFormProps, getInputProps, useForm } from "@conform-to/react";
import { parseWithZod } from "@conform-to/zod";
import { useActionState } from "react";
import { verify } from "./action";
import { mySchema } from "./schema";

export function MyForm() {
  const [lastResult, action] = useActionState(myServerAction, undefined);
  const [form, fields] = useForm({
    lastResult,
    onValidate({ formData }) {
      return parseWithZod(formData, {
        schema: mySchema,
      });
    },
  });

  return (
    <form {...getFormProps(form)} action={action}>
      <div>
        <input {...getInputProps(fields.name, { type: "text" })} />
        {fields.name.errors && <p>{fields.name.errors}</p>}
      </div>

      <button type="submit">Submit</button>
    </form>
  );
}

juanmarin-co avatar Oct 31 '24 13:10 juanmarin-co

As I said, I am not using server actions (at all)

stabildev avatar Oct 31 '24 13:10 stabildev

const [lastResult, setLastResult] = useState();
const [form, fields] = useForm<CreateUserInput>({
    lastResult,
    shouldValidate: "onSubmit",
    shouldRevalidate: "onInput",
    onValidate: ({ formData }) => parseWithZod(formData, { schema: createUserSchema }),
    onSubmit: (e, { submission }) => {
      e.preventDefault();
      if (submission?.status !== "success") return;
      try {
        await createUser(submission.value);
      } catch (e) {
        setLastResult(submission.reply({ fieldsErrors: { email: ["Invalid email"] } }));
    },
});

edmundhung avatar Oct 31 '24 13:10 edmundhung

Right :)

juanmarin-co avatar Oct 31 '24 13:10 juanmarin-co