首页 > 解决方案 > 使用不同的属性多次调用 form_widget - Symfony & Twig

问题描述

我试图用不同的属性多次在我的表单中调用表单小部件。我收到错误消息-Field "x" has already been rendered, save the result of previous render call to a variable and output that instead.

我已经在所有可以修复的地方进行了修复,但是有些字段需要不同的属性。例如 :-

form_widget(foo.bar, {'value' : 'image'}) }}

form_widget(foo.bar, { 'attr': { 'class': 'hidden' }} )

是否有可能在同一个表单上调用具有不同参数的表单小部件?

标签: symfonytwig

解决方案


像你一样多次重用同一个小部件可能会产生奇怪的副作用,因为 Symfony 也会设置一个 html id,并且根据你放置字段的位置,你可能最终会得到无效的 html,这可能会导致你的 JavaScript 中断/执行奇怪的事情或提交表单。

确保您拥有有效 HTML(例如,没有重复的 id)的最安全方法是手动渲染每个元素,然后仅使用表单元素来获取当前内容/错误。为了做到这一点,您可以忽略form_widgetform_row帮助器,只需自己编写字段的 HTML,然后只插入您需要的部分,例如

<input name="{{ field_name(foo.bar) }}" type="file">

这个确切的例子需要 Symfony 5.2,因为field_name()它是新的。见https://symfony.com/blog/new-in-symfony-5-2-form-field-helpers

不利的一面是,类似的东西{{ form_rest(form) }}可能不再起作用,但至少你仍然可以使用任何只输出不是表单元素的表单部分的助手,例如form_errorform_label应该仍然可以工作,但form_widgetform_row应该避免。form_end再次呈现所有剩余的字段,这就是为什么您可能也应该避免这种情况。Symfony 5.2 中引入的更具体的帮助器对于这种方法也非常方便。通过这种方式,您可以完全控制字段的呈现方式,并且可以更改您在多个位置使用的每个字段的类。

如果您使用旧版本的 Symfony,您可以通过查看提供它们的 TwigExtension并为您的应用程序调整它来自​​己实现辅助方法,例如提供您自己的具有类似功能的 AppTwigExtension。

如果你想继续使用form_widget/form_row那么你应该避免在同一个请求中多次渲染同一个表单(元素)。您可以尝试使用 sub-requres/ESI 之类的东西,但它可能会很麻烦。

有多种方法可以多次渲染表单,允许您每次都以不同的方式渲染它。例如,您可以创建一个 FormCollection,其中添加了两次相同的类型。然后你有一个包含 2 个表单的表单(你的表单两次)。您还可以为同一个表单创建多个实例,然后根据您使用的一个(foo 或 bar)在模板中以不同的方式呈现它们,例如类似的东西(只是粗略的轮廓,不确定这是否真的有效):

public function contact(Request $request): Response
{
    $form1 = $this->createForm(FooFormType::class, null, ['attr' => ['id' => 'form1']]);
    $form1->handleRequest($request);
    if ($form1->isSubmitted() && $form1->isValid() {
        // ...
    }

    $form2 = $this->createForm(FooFormType::class, null, ['attr' => ['id' => 'form1']]);
    $form2->handleRequest($request);
    if ($form2->isSubmitted() && $form2->isValid() {
        // ...
    }
    // Do something

    return $this->render('....html.twig', [
        'foo' => $form1->createView(),
        'bar' => $form2->createView(),
    ]);
}

如您所见,这有点多余,因此通常您希望避免这种方法,但是您应该在网上找到一些人们做类似事情的例子。


推荐阅读