You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现shadcn Dialog内嵌表单仅成功提交时关闭?

解决Dialog内嵌表单仅提交成功时关闭弹窗的问题

问题背景

当前在shadcn的Dialog组件内嵌了基于react-hook-form与zod构建的表单,将提交按钮包裹在DialogClose组件中后,无论表单提交成功与否弹窗都会关闭。需求是仅在表单提交成功时关闭Dialog,询问是否可将DialogClose作为函数使用及实现方式。

解决方案

Radix UI的DialogClose是组件而非函数,无法直接通过函数调用触发关闭。但可以通过Dialog的状态控制方法手动实现仅成功时关闭弹窗,具体步骤如下:

  • 传递Dialog的状态控制方法:修改PecuniaForm的Props,添加用于控制Dialog显示/隐藏的setOpen方法(该方法来自Dialog组件的状态或useDialog钩子)。
  • 移除DialogClose包裹:将提交按钮外的DialogClose组件移除,改为直接渲染Button。
  • 成功时手动关闭Dialog:在表单提交成功的逻辑分支中,调用setOpen(false)关闭弹窗。

修改后的完整表单代码

import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { useForm } from 'react-hook-form'
import { pecuniaFormSchema } from './PecuniaFormSchema'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { Button } from '@/components/ui/button'
import { updateFinancialRequest } from '@/app/services/financialService'
import { ErrorMapping } from '@/utils/errorMapping'
import { useToast } from '@/components/ui/use-toast'
import { objectToFormData } from '@/utils/objectToFormData'

// 新增Props:接收Dialog的状态控制方法
interface PecuniaFormProps {
  pecuniaId: number
  setOpen: (open: boolean) => void
}

export default function PecuniaForm({ pecuniaId, setOpen }: PecuniaFormProps) {
  const form = useForm<z.infer<typeof pecuniaFormSchema>>({
    resolver: zodResolver(pecuniaFormSchema),
  })
  const { toast } = useToast()

  async function handleSubmitData(values: z.infer<typeof pecuniaFormSchema>) {
    let erroTreatment
    try {
      const response = await updateFinancialRequest(
        objectToFormData({
          ...values,
          id: pecuniaId,
        }),
      )

      if (response !== 'SUCCESS_UPDATE') {
        erroTreatment = ErrorMapping(response.technicalMessage)
        throw new Error(`Response status: ${response.status}`)
      }

      toast({
        title: 'Dados financeiro atualizados com sucesso',
        duration: 3000,
      })
      // 提交成功后手动关闭Dialog
      setOpen(false)
    } catch (err) {
      toast({
        variant: 'destructive',
        title: erroTreatment || 'Erro ao realizar solicitação',
        duration: 4000,
      })
    }
  }

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(handleSubmitData)}
        className="space-y-8"
      >
        <FormField
          control={form.control}
          name="numeroEmpenho"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Número de Empenho</FormLabel>
              <FormControl>
                <Input
                  placeholder="Digite o valor de empenho"
                  type="number"
                  {...field}
                  onChange={(e) =>
                    field.onChange(
                      e.target.value === ''
                        ? undefined
                        : Number(e.target.value),
                    )
                  }
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="ob"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Ordem Bancária</FormLabel>
              <FormControl>
                <Input
                  placeholder="Digite o valor de OB"
                  type="number"
                  {...field}
                  onChange={(e) =>
                    field.onChange(
                      e.target.value === ''
                        ? undefined
                        : Number(e.target.value),
                    )
                  }
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="liquidacao"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Número de Liquidação</FormLabel>
              <FormControl>
                <Input
                  placeholder="Digite o valor de Liquidação"
                  type="number"
                  {...field}
                  onChange={(e) =>
                    field.onChange(
                      e.target.value === ''
                        ? undefined
                        : Number(e.target.value),
                    )
                  }
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="anexoFinanceiro"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Anexo Financeiro</FormLabel>
              <FormControl>
                <Input
                  type="file"
                  onChange={(e) => {
                    const file = e.target.files?.[0]
                    field.onChange(file)
                  }}
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        {/* 移除DialogClose包裹,直接渲染提交按钮 */}
        <Button type="submit">Confirmar Solicitação</Button>
      </form>
    </Form>
  )
}

父组件中传递状态控制方法示例

import { useState } from 'react'
import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'
import PecuniaForm from './PecuniaForm'
import { Button } from '@/components/ui/button'

export default function ParentComponent() {
  const [open, setOpen] = useState(false)
  const pecuniaId = 123 // 示例ID

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button>Abrir Formulário</Button>
      </DialogTrigger>
      <DialogContent>
        {/* 将setOpen传递给表单组件 */}
        <PecuniaForm pecuniaId={pecuniaId} setOpen={setOpen} />
      </DialogContent>
    </Dialog>
  )
}

内容的提问来源于stack exchange,提问作者Mittzera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:06:17