如何在Symfony 2表单中自定义data-prototype属性

j.2*_*2bb 53 forms collections symfony

从umpteens时代起,我就阻止了Symfony 2和表格的问题.

我有一种形式的网站实体."网站"是网站实体的集合,每个网站包含两个属性:"类型"和"网址".

如果我想在我的数据库中添加更多的网站,我可以点击"添加其他网站"链接,这会在我的表单中添加另一个网站行.因此,当您单击提交按钮时,您可以同时添加一个或X个网站.

这个添加行的过程使用data-prototype属性,它可以生成网站子表单.

问题是我自定义我的表单以获得一个很棒的图形渲染......就像这样:

<div class="informations_widget">{{ form_widget(website.type.code) }}</div>
<div class="informations_error">{{ form_errors(website.type) }}</div>
<div class="informations_widget">{{ form_widget(website.url) }}</div>
<div class="informations_error">{{ form_errors(website.url) }}</div>
Run Code Online (Sandbox Code Playgroud)

但是数据原型不关心这种自定义,使用HTML和CSS标签和属性.我保留了Symfony渲染:

<div>
<label class=" required">$$name$$</label>
<div id="jobcast_profilebundle_websitestype_websites_$$name$$">
<div>
<label class=" required">Type</label>
<div id="jobcast_profilebundle_websitestype_websites_$$name$$_type">
<div>
<label for="jobcast_profilebundle_websitestype_websites_$$name$$_type_code" class=" required">label</label>
<select id="jobcast_profilebundle_websitestype_websites_$$name$$_type_code" name="jobcast_profilebundle_websitestype[websites][$$name$$][type][code]" required="required">
<option value="WEB-OTHER">Autre</option>
<option value="WEB-RSS">Flux RSS</option>
...
</select>
</div>
</div>
</div>
<div>
<label for="jobcast_profilebundle_websitestype_websites_$$name$$_url" class=" required">Adresse</label>
<input  type="url" id="jobcast_profilebundle_websitestype_websites_$$name$$_url" name="jobcast_profilebundle_websitestype[websites][$$name$$][url]" required="required" value="" />
</div>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)

有没有人有想法制作那个黑客?

Jiv*_*van 73

有点旧,但这是一个致命的简单解决方案.

这个想法只是通过Twig模板渲染集合项,因此您可以完全自定义将放置在data-prototype="..."标记中的原型.就像它是一个正常的,通常的形式.

在yourMainForm.html.twig中:

<div id="collectionContainer"
     data-prototype="
         {% filter escape %}
             {{ include('MyBundle:MyViewsDirectory:prototype.html.twig', { 'form': form.myForm.vars.prototype }) }}
         {% endfilter %}">
</div>
Run Code Online (Sandbox Code Playgroud)

在MyBundle中:MyViewsDirectory:prototype.html.twig:

<div>
    <!-- customize as you wish -->
    {{ form_label(form.field1) }}
    {{ form_widget(form.field1) }}
    {{ form_label(form.field2) }}
    {{ form_widget(form.field2) }}
</div>
Run Code Online (Sandbox Code Playgroud)

信用:改编自https://gist.github.com/tobalgists/4032213

  • 非常有帮助,谢谢!此外,它可能是常识,但如果你要走这条路线,不要在树枝模板中包含form_start和form_end函数.我发现了包括那些导致数据库持久存在问题的困难方法. (2认同)
  • 当实体已经在集合中有项目时,这应该也可以工作吗?对我来说,自定义模板仅适用于新条目 (2认同)

Akk*_*tor 47

我知道这个问题已经很老了,但是我遇到了同样的问题,这就是我的问题.我正在用一根小树枝macro来完成这件事.宏类似于函数,您可以使用不同的参数渲染它们.

{% macro information_prototype(website) %}
    <div class="informations_widget">{{ form_widget(website.type.code) }}</div>
    <div class="informations_error">{{ form_errors(website.type) }}</div>
    <div class="informations_widget">{{ form_widget(website.url) }}</div>
    <div class="informations_error">{{ form_errors(website.url) }}</div>
{% endmacro %}
Run Code Online (Sandbox Code Playgroud)

现在,您可以在任何地方渲染此宏.请注意,这information_prototype()只是宏的名称,您可以根据需要为其命名.如果您想使用宏以相同的方式呈现给定的项目和原型,请执行以下操作:

<div class="collection" data-prototype="{{ _self.information_prototype(form.websites.vars.prototype)|e }}">
    {% for website in form.websites %}
        {{ _self.information_prototype(website) }}
    {% endfor %}
    <button class="add-collection">Add Information</button>
</div>
Run Code Online (Sandbox Code Playgroud)

form.websites.vars.prototype保存表单的原型数据和prototype_name您指定的.使用_self.+macroname,如果你想使用宏在同一个模板.

您可以在Twig文档中找到有关宏的更多信息

  • 这个答案应该被标记为最好和最简单的答案!谢谢! (2认同)

Fra*_*ant 25

你可能已经发现了,但这里是其他人的解决方案.

创建一个新模板并将此代码复制/粘贴到其中:https: //gist.github.com/1294186

然后在包含要自定义的表单的模板中,通过执行以下操作将其应用于表单:

{% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %}
Run Code Online (Sandbox Code Playgroud)

  • 该模板非常适合迭代集合并根据需要渲染所有集合.留言Merci (2认同)

小智 5

我知道答案很晚,但对游客来说可能很有用.

在您的主题文件中,您只需使用一个块来呈现网站小部件的每个集合条目,如下所示:

{% block _jobcast_profilebundle_websitestype_websites_entry_widget %}
     <div class="informations_widget">{{ form_widget(form.type.code) }}</div>
     <div class="informations_error">{{ form_errors(form.type) }}</div>
     <div class="informations_widget">{{ form_widget(form.url) }}</div>
     <div class="informations_error">{{ form_errors(form.url) }}</div>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)

还为您的集合小部件行创建主题块,如下所示:

{% block _quiz_question_answers_row %}
     {% if prototype is defined %}
        {%- set attr = attr | merge({'data-prototype': form_row(prototype) }) -%}
    {% endif %}

     {{ form_errors(form) }}

     {% for child in form %}
         {{ form_row(child) }}
     {% endfor %}
{% endblock %}
Run Code Online (Sandbox Code Playgroud)

现在原型和渲染的集合条目将是相同的.


Krz*_*ski 5

我最近遇到了类似的问题.以下是如何覆盖集合原型而无需在html中明确设置它:

{% set customPrototype %}
    {% filter escape %}
        {% include 'AcmeBundle:Controller:customCollectionPrototype.html.twig' with { 'form': form.collection.vars.prototype } %}
    {% endfilter %}
{% endset %}
{{ form_label(form.collection) }}
{{ form_widget(form.collection, { 'attr': { 'data-prototype': customPrototype } }) }}
Run Code Online (Sandbox Code Playgroud)

你可以在你的自定义树枝上做任何你想做的事.例如:

<div data-form-collection="item" data-form-collection-index="__name__" class="collection-item">
<div class="collection-box col-sm-10 col-sm-offset-2 padding-top-20">
    <div class="row form-horizontal form-group">
        <div class="col-sm-4">
            {{ form_label(form.field0) }}
            {{ form_widget(form.field0) }}
        </div>
        <div class="col-sm-3">
            {{ form_label(form.field1) }}
            {{ form_widget(form.field1) }}
        </div>
        <label class="col-sm-3 control-label text-right">
            <button data-form-collection="delete" class="btn btn-danger">
                <i class="fa fa-times collection-button-remove"></i>{{ 'form.collection.delete'|trans }}
            </button>
        </label>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

当您只需要在特定位置执行此操作并且不需要适用于所有集合的全局覆盖时,此选项非常有用.


Lou*_*une 1

应用程序范围的表单主题将应用于原型。请参阅进行应用程序范围的自定义