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

因为在几天的时间里,我阻止了Symfony 2和表格的问题。

我有一个网站实体的forms。 “网站”是网站实体的集合,每个网站包含两个属性:“types”和“url”。

如果我想在我的数据库中添加更多的网站,我可以点击一个“添加另一个网站”链接,在我的表单中添加另一个网站。 所以当你点击提交button时,你可以同时添加一个或X个网站。

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

问题是,我自定义我的窗体有一个伟大的graphics渲染…像这样:

<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> 

但数据原型不关心这个定制,与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> 

有没有人有一个想法,使黑客?

有点老,但这是一个致命的简单的解决scheme。

这个想法只是简单地通过一个Twig模板渲染集合项目,所以你完全有能力定制将放置在你的data-prototype="..."标记中data-prototype="..." 。 就好像它是一个正常的,通常的forms。

在您的MainForm.html.twig中:

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

在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> 

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

我知道这个问题已经很老了,但是我也遇到了同样的问题,我就是这样的。 我正在使用树枝macro来实现这一点。 macros就像函数一样,你可以用不同的参数来渲染它们。

 {% 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 %} 

现在你可以渲染这个macros,无论你想要的。 请注意, information_prototype()只是macros的名称,您可以将其命名为任何您想要的名称。 如果您想使用macros以相同的方式渲染给定的项目和原型,请执行以下操作:

 <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> 

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

您可以在Twig文档中find有关macros的更多信息

你可能已经发现,但这里是其他人的解决scheme。

创build一个新的模板,并复制/粘贴这个代码: https : //gist.github.com/1294186

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

 {% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %} 

我最近遇到类似的问题。 以下是如何重写集合原型,而不必在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 } }) }} 

你可以做任何你想要的然后在你的自定义小枝。 例如:

 <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> 

如果您只需在特定位置执行此操作,并且不需要适用于所有集合的全局覆盖,就很有用。

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

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

 {% 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 %} 

还可以为您的collections小部件行创build主题块,如下所示:

 {% 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 %} 

现在原型和渲染的收集条目将是相同的。

我有一个类似的问题。 您可能需要调整此function以适应您的情况,但有人可能会发现它有帮助。

创build一个新的模板文件来保存您的自定义窗体“主题”

 ./src/Company/TestBundle/Resources/views/Forms/fields.html.twig 

通常,您可以使用form_row函数来显示字段的标签,错误和小部件。 但在我的情况下,我只是想显示小部件。 正如你所说,使用数据原型function也会显示标签,所以在我们新的fields.html.twig中input你想要的字段的自定义代码:

 {% block form_row %} {% spaceless %} {{ form_widget(form) }} {% endspaceless %} {% endblock form_row %} 

我删除了容器div,标签和错误,只是离开了小部件。

现在,在显示表单的树枝文件中,只需在{%extends …%}之后添加它,

 {% form_theme form 'CompanyTestBundle:Form:fields.html.twig' %} 

而现在form_widget(form.yourVariable.var.prototype)将只呈现该字段,而不是别的。

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

这里是自定义数据原型的示例代码:

 {{ form_widget(form.emails.get('prototype')) | e }} 

emails – 您的collections。

要定制不同的现有集合项VS原型,可以像这样覆盖collection_widget:

 {%- block collection_widget -%} {% if prototype is defined %} {%- set attr = attr|merge({'data-prototype': form_row(prototype, {'inPrototype': true} ) }) -%} {% endif %} {{- block('form_widget') -}} {%- endblock collection_widget -%} 

然后在您的自定义条目中:

 {% block _myCollection_entry_row %} {% if(inPrototype is defined) %} {# Something special only for prototype here #} {% endif %} {% endblock %} 

如果你不需要在系统范围内定义一个模板,只需在你的树枝模板中设置一个模板,并要求树枝使用它。

 {# using the profiler, you can find the block widget tested by twig #} {% block my_block_widget %} <div > <p>My template for collection</p> <div > {{ form_row(form.field1)}} </div> <div> {{ form_row(form.field2)}} </div> </div> {% endblock %} {% form_theme form.my_collection _self %} <button data-form-prototype="{{ form_widget(form.my_collection.vars.prototype) )|e }}" >Add a new entry</button> 

这篇文章重点介绍在树枝模板中使用预先存在的约定。

基于Symfony Cookbook( http://symfony.com/doc/master/cookbook/form/form_collections.html )中的“如何embedded表单集合”,您可以在数据中input希望的任何html_escaped表单数据 – 原型(可能被认为是黑客,但奇妙的作品),只有使用该模板的网页会改变。

在这个例子中,他们告诉你把:

  <ul class="tags" data-prototype="{{ form_widget(form.tags.vars.prototype)|e }}"> ... </ul> 

这可以被成功地replace为诸如以下的东西:

 <table class="tags" data-prototype="&lt;tr&gt; &lt;td&gt;&lt;div&gt;&lt;input type=&quot;text&quot; id=&quot;task_tags__name__tagId&quot; name=&quot;task[tags][__name__][taskId]&quot; disabled=&quot;disabled&quot; required=&quot;required&quot; size=&quot;10&quot; value=&quot;&quot; /&gt;&lt;/div&gt;&lt;/td&gt; &lt;td&gt;&lt;div&gt;&lt;input type=&quot;text&quot; id=&quot;task_tags__name__tagName&quot; name=&quot;task[tags[__name__][tagName]&quot; required=&quot;required&quot; value=&quot;&quot; /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;"> <tr> <th>Id</th> <th>Name</th> </tr> <tr> ...pre existing data here... </tr> </table> 

如果上面带有“tags”类的表的data-type属性是html转义版本(并且换行符被删除(虽然空格是可以的并且是必需的):

 <tr> <td><div><input type="text" id="task_tags__name__tagId" name="task[tags][__name__][taskId]" disabled="disabled" required="required" size="10" value="" /></div></td> <td><div><input type="text" id="task_tags__name__tagName" name="task[tags[__name__][tagName]" required="required" value="" /></div></td> </tr> 

…但你也必须在示例中调整javascript来添加tr而不是li元素:

 function addTagForm(collectionHolder, $newLinkTr) { ... // Display the form in the page in an tr, before the "Add a question" link tr var $newFormTr = $('<tr></tr>').append(newForm); ... }; ... // setup an "add a tag" link var $addTagLink = $('<a href="#" class="add_tag_link">Add a tag</a>'); var $newLinkTr = $('<tr></tr>').append($addTagLink); ... 

对我来说,下一步是弄清楚如何在一个外部文件中定义原型,我可以在树枝模板中调用与表单dynamic一致的数据原型。 就像是:

 <table class="tags" data-prototype="{{somefunction('App\Bundle\Views\Entity\TagsPrototypeInTable')}}"> 

所以如果其他的post之一是描述这个,我太密集,或者如果有人知道如何这样做,这样说!

有一个从弗朗索瓦的gitHub的链接,但我没有看到任何解释,所以我认为这可能是更有活力的方法,我会得到这些近期日子之一。

和平,史蒂夫

更新:

也可以使用原型的一部分:

 data-prototype="&lt;tr&gt; &lt;td&gt;{{ form_row(form.tags.vars.prototype.tagId) | e }}&lt;/td&gt; &lt;td&gt;{{ form_row(form.tags.vars.prototype.tagName) | e }}&lt;/td&gt;&lt;/tr&gt;" 

如果上面带有“tags”类的表的data-type属性是html转义版本(并且换行符被删除(虽然空格是可以的并且是必需的):

 <td>{{ form_row(form.tags.vars.prototype.tagId) | e }}</td> <td>{{ form_row(form.tags.vars.prototype.tagName) | e }}</td> 

(我使用http://www.htmlescape.net/htmlescape_tool.html 。)

当页面被渲染时,Symfony会将{{}}和html_escaped(因为“| e”)渲染字段之间的信息replace。 这样,任何在现场级别的定制都不会丢失,但是! 你必须手动添加和删除字段的原型,因为你这样做的实体:)