【问题标题】:Symfony2 form: How to render the same element twice in the same viewSymfony2表单:如何在同一个视图中两次渲染同一个元素
【发布时间】:2013-02-04 08:23:22
【问题描述】:

我有一个控制器,我在其中创建一个带有两个下拉列表的表单。

当我渲染我的视图时,我希望在页面的顶部和底部有相同的表单元素。问题是表单 elemetns(下拉列表)仅显示在页面顶部,即使我要求 twig 将它们也放在底部。

这是我想要的:

1 和 2 是下拉列表。我想在页面的顶部和底部复制它。

关于如何做到这一点的任何想法?

两个下拉列表所在的顶部内容和底部内容位于一个单独的 twig 文件 (searchPanel.html.twig) 中,并且该文件包含在页面中

{% include "MyBundle:Search:searchPanel.html.twig" %}

这里是 searchPanel.html.twig

<div class="searchPanel">

<form action="{{ path }}" method="POST" {{ form_enctype(form) }}>
    Papers per page
    {{ form_widget(form.papers_per_page, { 'class': 'ppp'}) }}

    / Sort by 
    {{ form_widget(form.sort_by, { 'class': 'sort'}) }}
    {{ form_rest(form) }}

    / Papers ({{ papers_number }} results)

 <input type="submit" class="updateSearchResults" value="Update"></input>
</form>

【问题讨论】:

  • 能贴一下searchPanel.html.twig的代码吗??
  • 是的,我会的。
  • 不要忘记将表单添加为参数 '{% include "MyBundle:Search:searchPanel.html.twig" with {'form' : form} %} 它应该可以工作
  • @JulienRollin,不幸的是,它不起作用。还是同样的问题。 :(
  • 这就是为什么要在您的小部件类/ID 中添加前缀(例如:'top' 和 'bottom')。您可以致电'{% include "MyBundle:Search:searchPanel.html.twig" with {'form' : form, 'prefix': 'top' } %}

标签: php symfony twig


【解决方案1】:

您的方法中的一个问题是 Symfony 的表单组件将呈现带有 id 的表单元素,如果您在页面上两次呈现相同的表单,则会重复这些元素。您可能还会遇到 csrf_token 问题。要点是表格不能被复制。

这就是我要做的。在不使用 Symfony\Form 的情况下创建一个包含分页器表单的 twig-template,即静态创建所有表单元素并将其传递给分页器对象(或数组)以获取数据,而不是使用 form_widget()。像这样的:

<form action="{{ path(app.request.attributes.get('_route') }}" method="POST">
    <select name="paginator[per_page]">
        {% for per_page in paginator.papers_per_page %}
        <option value=""{{ per_page }}">{{ per_page }}</option>
        {% endfor %}
    </select>
</form>

表单动作会自动将数据提交到您当前的路由,因此您可以将其嵌入到不同的动作中,它会将数据提交给同一个动作。在 POST 上,您可以使用 post-data 创建一个分页器对象,然后将其添加为表单的数据。之后,您只需照常使用 isValid() 即可。

在您的控制器中,您可以像这样获取数据:

use Symfony\Component\HttpFoundation\Request;
// ...

public function PaperController()
{
    public function listAction(Request $request)
    {
        if ($request->getMethod() == 'POST') {
            $data = $request->request->get('paginator');
            $paginator = new Paginator($data);

            $form = new PaginatorFormType();
            $form->setData($paginator);

            if ($form->isValid()) {
                // ...
            }
        }
    }
}

您可以像这样轻松地将表单嵌入到您的视图中:

{{ include 'AcmeDemoBundle:Form:paginator.html.twig' with { 'paginator': paginator } }}

基本上,您只需将控制器中的表单组件用于验证目的。如果您想设置一些默认值或添加其他参数,您可能需要从该模板创建一个macro,但对于您的用例,这应该足够了。也许其他人有更好的解决方案,但这就是我在一个项目中遇到类似问题的方式。

【讨论】:

  • 谢谢。那么,我将不得不在模板中手动(静态)创建表单,而不是使用经典表单?如果我需要更多帮助,我会尝试这种方法并回复您。
  • 基本上,是的。同样,可能还有其他方法可以重用表单组件。但是这种方法对我来说效果很好,实际上很容易重复使用,例如当您有多个需要分页的操作时。 P.S.:如果你想通过 URL 参数设置页码或 items_per_page 你可以这样做:{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({ 'page_number': paginator.current_page + 1 })) }}
  • 我正在尝试让您的解决方案在我的示例中运行。现在,我的 searchPanel 模板中有手动表单。如何在我的控制器中获取 onSubmit 的数据?
  • @Milos 我用您的控制器的示例列表更新了我的答案。还要寻找表单示例,您想使用类似于表单组件的数组表示法。如果您不确定我的意思,请检查通过 Symfony\Component\Form 生成的表单中的 html。您可能希望手动将每个属性添加到分页器,而不是将数组传递给构造函数,或者只使用表单中的数组并完全跳过分页器;这只是一个让您入门的基本示例。如果您遇到困难,请随时询问更多详细信息。
  • 非常感谢,现在效果很好。最后一个问题,你知道twig中是否有一个“不错”的选项来设置我的下拉列表的默认选定项。我知道我可以检查 fith if 然后手动设置默认选定项,但可能还有其他一些解决方案可以在一行中设置默认选定元素。
【解决方案2】:

另一个选项是用户渲染树枝助手。这样就可以根据需要多次在页面中呈现相同的表单。不同的是,使用这个助手,也需要将表单呈现作为一个独立的控制器动作,即: 在你的树枝模板的每个地方,你想在助手中呈现表单以调用表单,必须是这样的:

{{ render(controller('BundleNameBundle:Controller:Action', {
    'param': paramId
})) }}

此后只是创建控制器的问题...

【讨论】:

  • 它比较重,因为每次调用 render 时,twig 都会编译渲染所需的模板(动态结果),但对于大规模渲染也是如此,因此在这种情况下,这可以忽略不计
【解决方案3】:

另一个选项是在控制器中创建 2 个表单:

 //first form
 $form = $this->createForm(new MyFormType(), ...);

 //second form: must have different form name that default,
 //to render in twig the fields with different ids
 $formType = new MyFormType();
 $formType->setName('second_form_name');
 $formSecond = $this->createForm($formType, ...);

在渲染 twig 表单时同时发送:

return $this->render( ... 
            'form' => $form->createView(), 'formSecond'=>$formSecond->createView()));

然后将第二个定义为

formSecond

,会和第一个冲突。

【讨论】:

    猜你喜欢
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多