ui icon indicating copy to clipboard operation
ui copied to clipboard

Form in dialog doesn't send the Request.

Open Nibycz opened this issue 1 year ago • 22 comments

Hello, i have a little Problem.

so thats my Code:

    <Dialog open={open} onOpenChange={setOpen}>
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)}>
          <DialogContent className="sm:max-w-[425px]">
            <DialogHeader>
              <DialogDescription>
                Make changes to your profile here. Click save when youre done.
              </DialogDescription>
            </DialogHeader>

            <FormField
              control={form.control}
              name="full_name"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Name</FormLabel>
                  <FormControl>
                    <Input placeholder="Name" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            <DialogFooter>
              <Button type="submit">Submit</Button>
            </DialogFooter>
          </DialogContent>
        </form>
      </Form>
    </Dialog>

That looks like

image

The Problem now is, that the Form doesnt send the Request. It should be, or am i wrong ?

When i move the <Form> into the <DialogContent> the Form works but the styles are wrong

image

Nibycz avatar Jun 25 '23 15:06 Nibycz

I have a similar setup, but I've separated the Form into its own component and nested it into the Dialog as shown below:

"use client"

/* a bunch of imports you don't care about */

export function TableDialogCustom() {

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline">Add Table</Button>
      </DialogTrigger>
      <DialogContent className="sm:max-w-[425px]">
        <DialogHeader>
          <DialogTitle>Add a Table</DialogTitle>
          <DialogDescription>
            Add a table name and a read-only API key from AirTable
          </DialogDescription>
        </DialogHeader>
        <div className="grid gap-4 py-4">
          <div className="grid items-center gap-4">
            <TableForm />
          </div>
        </div>
      </DialogContent>
    </Dialog>
  )
}
"use client"

/* a bunch of imports you don't care about */

export function TableForm() {

    /* a bunch of resolver/onclick stuff you don't care about */

    return (
        <Form {...form}>
            <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
            <FormField
                control={form.control}
                name="table_name"
                render={({ field }) => (
                <FormItem>
                    <FormLabel>Username</FormLabel>
                    <FormControl>
                        <Input placeholder="Table Name" {...field} />
                    </FormControl>
                    <FormDescription>
                    Enter your table name here.
                    </FormDescription>
                    <FormMessage />

                </FormItem>
                
                )}
            />
            <FormField
                control={form.control}
                name="api_key"
                render={({ field }) => (
                <FormItem>
                    <FormLabel>API Key</FormLabel>
                    <FormControl>
                        <Input placeholder="API Key" {...field} />
                    </FormControl>
                    <FormDescription>
                    Enter your API Key here.
                    </FormDescription>
                    <FormMessage />
                    
                </FormItem>
                
                )}
            />
            <Button type="submit">Submit</Button>
            </form>
        </Form>
        )
}

It ends up looking like this: Screen Recording 2023-06-26 at 1 27 42 PM

mollukaren avatar Jun 26 '23 17:06 mollukaren

still not working 😢

d4v44khuu avatar Jul 21 '23 21:07 d4v44khuu

@daddotmn use button onClick and dispatch submit event with bubbles true

  <Form {...form}>
          <form ref={formRef} onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
              ...
          </form>
  </Form>
  ...
  <Button
    onClick={() => {
      if (formRef.current) {
        formRef.current.dispatchEvent(new Event('submit', { bubbles: true }));
      }
    }}
  >
    Continue
  </Button>

Chanran avatar Jul 29 '23 13:07 Chanran

@daddotmn use button onClick and dispatch submit event with bubbles true

  <Form {...form}>
          <form ref={formRef} onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
              ...
          </form>
  </Form>
  ...
  <Button
    onClick={() => {
      if (formRef.current) {
        formRef.current.dispatchEvent(new Event('submit', { bubbles: true }));
      }
    }}
  >
    Continue
  </Button>

This works fine... but this should work without this workaround.

0xlinus avatar Aug 02 '23 15:08 0xlinus

If you are rendering the form outside the Dialog.Content, what is happening is that the button is being portaled to the body and as it is not inside the form element the submit will not work. What you can do is:

  • Move the form into Dialog.Content
  • Use the form attribute on the submit button

joaom00 avatar Aug 02 '23 16:08 joaom00

what to do if in case we have a long form containing various fields.. in my case the dialog just scatter height wise due to large no. of fields. i somehow want to adjust the dialog on the screen and scroll the form fields. note: scrollarea isn't working at all in this case.

kgaurav152 avatar Aug 20 '23 21:08 kgaurav152

@daddotmn use button onClick and dispatch submit event with bubbles true

  <Form {...form}>
          <form ref={formRef} onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
              ...
          </form>
  </Form>
  ...
  <Button
    onClick={() => {
      if (formRef.current) {
        formRef.current.dispatchEvent(new Event('submit', { bubbles: true }));
      }
    }}
  >
    Continue
  </Button>

even this doesn't work for me. anybody has a solution for this?

miljan-code avatar Aug 23 '23 16:08 miljan-code

I found this: https://github.com/react-hook-form/react-hook-form/issues/566#issuecomment-612328736

There seem to be several solutions.

  1. If you have access to handleSubmit() function in the component which includes your submit button: invoke it directly handleSubmit(onSubmit)().
  2. You can set an id on your <form id="my-form" >, and add this id to the form attribute of your submit button: <button type="submit" form="my-form" />.

Option 1 seems easiest and solved my problem. Option 2 triggered a full page refresh/rerender so i didn't use it.

mrxsal avatar Aug 23 '23 21:08 mrxsal

To resolve this I moved the <Form {...form}/> component to wrap the entire <Dialog> component and placed the submit button inside the <DialogContent>.

Here's the code:

const formSchema = z.object({
  is_business: z.boolean().default(false),
  // more schema here...
});

export default function NewCxDialog({ open, onOpenChange }) {
  const { handleSubmit, control, ...form } = useForm({
    resolver: zodResolver(formSchema),
    defaultValues: {
      is_business: false,
     // default values here...
    },
  });

  function onSubmit(e) {
    function closeDialog() {
      onOpenChange(false);
    }

    const submitData = async (e) => {
      try {
        const response = await fetch("/api/new/cx", {
          method: "POST",
          cache: "no-store",
          body: JSON.stringify(e),
          headers: {
            "Content-Type": "application/json",
          },
        });
      } catch (error) {
        throw error;
      }
    };

    // I use sonner for toasts
    toast.promise(submitData(), {
      loading: "Cargando...",
      success: () => {
        router.refresh();
        closeDialog();
        return "Cliente Creado Exitosamente";
      },
      error: (e) => {
        console.error(e);
        return "Hubo un error. Intenta nuevamente.";
      },
    });
  }

  return (
    <Form {...form}>
      <Dialog
        open={open}
        onOpenChange={() => {
          form.reset();
          onOpenChange();
        }}
      >
        <DialogContent className="max-w-2xl">
          <form onSubmit={handleSubmit(onSubmit)}>
            <DialogHeader>
              <DialogTitle className="!text-primary">
                Crear Nuevo Cliente
              </DialogTitle>
              <DialogDescription>
                Llena el formulario con la información de tu cliente.
              </DialogDescription>
            </DialogHeader>
            <div className="grid gap-6 py-4">
              <div className="grid grid-cols-2 gap-6">
                <FormField
                  control={control}
                  name="first_name"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Nombre</FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
                <FormField
                  control={control}
                  name="last_name"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Apellido</FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
               // more code here...
              </div>
            </div>
            <DialogFooter>
              <Button type="submit">Crear Cliente</Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </Form>
  );
}

delfincortesb avatar Sep 12 '23 22:09 delfincortesb

If you are rendering the form outside the Dialog.Content, what is happening is that the button is being portaled to the body and as it is not inside the form element the submit will not work. What you can do is:

  • Move the form into Dialog.Content
  • Use the form attribute on the submit button

Cleanest explanation. Works as expected now. Ty @joaom00

sartoshi-foot-dao avatar Oct 30 '23 15:10 sartoshi-foot-dao

If you are rendering the form outside the Dialog.Content, what is happening is that the button is being portaled to the body and as it is not inside the form element the submit will not work. What you can do is:

  • Move the form into Dialog.Content
  • Use the form attribute on the submit button

Cleanest explanation. Works as expected now. Ty @joaom00

It's not working

caanyp24 avatar Dec 07 '23 19:12 caanyp24

To resolve this I moved the <Form {...form}/> component to wrap the entire <Dialog> component and placed the submit button inside the <DialogContent>.

Here's the code:

const formSchema = z.object({
  is_business: z.boolean().default(false),
  // more schema here...
});

export default function NewCxDialog({ open, onOpenChange }) {
  const { handleSubmit, control, ...form } = useForm({
    resolver: zodResolver(formSchema),
    defaultValues: {
      is_business: false,
     // default values here...
    },
  });

  function onSubmit(e) {
    function closeDialog() {
      onOpenChange(false);
    }

    const submitData = async (e) => {
      try {
        const response = await fetch("/api/new/cx", {
          method: "POST",
          cache: "no-store",
          body: JSON.stringify(e),
          headers: {
            "Content-Type": "application/json",
          },
        });
      } catch (error) {
        throw error;
      }
    };

    // I use sonner for toasts
    toast.promise(submitData(), {
      loading: "Cargando...",
      success: () => {
        router.refresh();
        closeDialog();
        return "Cliente Creado Exitosamente";
      },
      error: (e) => {
        console.error(e);
        return "Hubo un error. Intenta nuevamente.";
      },
    });
  }

  return (
    <Form {...form}>
      <Dialog
        open={open}
        onOpenChange={() => {
          form.reset();
          onOpenChange();
        }}
      >
        <DialogContent className="max-w-2xl">
          <form onSubmit={handleSubmit(onSubmit)}>
            <DialogHeader>
              <DialogTitle className="!text-primary">
                Crear Nuevo Cliente
              </DialogTitle>
              <DialogDescription>
                Llena el formulario con la información de tu cliente.
              </DialogDescription>
            </DialogHeader>
            <div className="grid gap-6 py-4">
              <div className="grid grid-cols-2 gap-6">
                <FormField
                  control={control}
                  name="first_name"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Nombre</FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
                <FormField
                  control={control}
                  name="last_name"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Apellido</FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
               // more code here...
              </div>
            </div>
            <DialogFooter>
              <Button type="submit">Crear Cliente</Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </Form>
  );
}

Doesn't this render an empty form in place until the Dialog renders a Portal?

josephdburdick avatar Dec 07 '23 22:12 josephdburdick

IF YOU ARE USING ANY KIND OF FORM RESOLVER: Apart from this above solutions on form there might be issue in your zod schema.If you forgot to add an required zod field schema in the form then there would'nt be any error in form but internally zod stop you from submitting the form.

Yogesh070 avatar Dec 09 '23 12:12 Yogesh070

IF YOU ARE USING ANY KIND OF FORM RESOLVER: Apart from this above solutions on form there might be issue in your zod schema.If you forgot to add an required field zod schema in the form then there would'nt be any error in form but internally zod stop you from submitting the form.

This solution works for me. Thank you @Yogesh070

justinwangdev avatar Dec 10 '23 22:12 justinwangdev

2. form="my-form"

Thank you! Solved it, there is no need to wrap around Dialog box. There was a problem with zod resolvers in my case and that fixed the problem.

Inthuson avatar Feb 22 '24 21:02 Inthuson

@kgaurav152 did ya manage to solve that issue?

imtheaman avatar Mar 07 '24 07:03 imtheaman

@kgaurav152 did ya manage to solve that issue?

Yes it's working for me. What I did is that I separately made the form and then imported that into the dialog component and it's working since then, have been using this same approach wherever needed and it's working.

 Const UpdateProfileForm

Const UpdateProfile
 <UpdateProfileForm/>

kgaurav152 avatar Mar 07 '24 20:03 kgaurav152

Worked for me too. i was not having an input component for a schema field and that's why it was invalid every time i submitted the form but i wasn't getting any error as i didn't have registered that schema field with any input component. after making that schema field optional, i got it working.

Thanks everyone.

imtheaman avatar Mar 11 '24 14:03 imtheaman

I faced the same issue myself, what I did is I wrapped the <Dialog> with my <Form> component and separated my

into a separate component
<Form {...form}> 
  <Dialog>
     <DialogTrigger></DialogTrigger>
     <DialogContent></DialogContent>
     
     // This is where my form lies (you can easily infer type with Zod from the schema)
     <ApplicationForm form={form} />

navi-05 avatar Mar 19 '24 05:03 navi-05

I encountered the same issue. moved from using <form /> to use useForm handle submit function on the button and it worked

  return (
    <Dialog>
      <DialogTrigger asChild>
        <button className="w-full text-start">Edit</button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Edit tag</DialogTitle>
          <DialogDescription>Edit tag information</DialogDescription>
          <Label htmlFor="name">Name</Label>
          <Input
            placeholder="Birthday"
            id="name"
            type="text"
            {...register("name", {
              required: { message: "Tag name is required", value: true },
              maxLength: {
                value: 30,
                message: "Tag Name cannot be grater than 30",
              },
            })}
          />
        </DialogHeader>
        <DialogFooter>
          <Button
            type="button"
            onClick={handleSubmit(handleEditTag)}
          >
            Update
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );

huilensolis avatar Apr 15 '24 15:04 huilensolis

Same issue with form not firing submit event when inside a Dialog: Changed from this :

       <form onSubmit={submitData}>   ---> from here
       <Dialog>
       <DialogTrigger asChild>
       <Button variant="outline">Add New Item</Button>
       </DialogTrigger>
      <DialogContent className="sm:max-w-[500px] w-[700px] ">
      
      ....

To this :

      
      <Dialog>
      <DialogTrigger asChild>
      <Button variant="outline">Add New Item</Button>
      </DialogTrigger>
      <DialogContent className="sm:max-w-[500px] w-[700px] ">
      <form onSubmit={submitData}>    ----> to here
       ....
   

dbanswan avatar May 08 '24 14:05 dbanswan

Please follow the method below to solve the problem.

<Dialog onOpenChange={setOpen} open={open}>
       <DialogContent>

                <DialogHeader>
                  <DialogTitle>
                    Are you absolutely sure to reject the request?
                  </DialogTitle>
                  <DialogDescription>
                    This action cannot be undone. This will permanently delete
                    your account and remove your data from our servers.
                  </DialogDescription>
                </DialogHeader>
                <Form {...form}>
                  <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-12">
                    <fieldset >
                      <FormField
                        control={form.control}
                        name="rejectComment"
                        render={({ field }) => {
                          return (
                            <FormItem>
                              <FormLabel>Reject comment</FormLabel>
                              <FormControl>
                                <Input placeholder="Reject comment" {...field} />
                              </FormControl>

                              <FormMessage />
                            </FormItem>
                          )
                        }}
                      />
                      <DialogFooter>
                        <Button className="my-2" type="submit">Save changes</Button>
                      </DialogFooter>
                    </fieldset>
                  </form>
                </Form>

              </DialogContent>
 </Dialog>

KhoeLe avatar Jun 14 '24 06:06 KhoeLe

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.

shadcn avatar Jul 12 '24 23:07 shadcn