使用不同的属性多次调用 form_widget - Symfony & Twig

Calling form_widget multiple times with different attributes - 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' }} )

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

多次重复使用同一个小部件,就像你这样做会产生奇怪的副作用,因为 Symfony 也会设置一个 html id 并且根据你放置字段的位置,你可能最终会得到无效的 html 例如,这可能会导致您的 JavaScript 出现 break/do 奇怪的事情,或者使提交表单变得古怪。

确保您拥有有效 HTML(例如没有重复 ID)的最安全方法是手动呈现每个元素,然后仅使用表单元素来获取当前 content/errors。为了做到这一点,您可以忽略 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 that provides them 并针对您的应用程序调整它来自​​己实现辅助方法,例如提供您自己的具有类似功能的 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(),
    ]);
}

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