How to set data-prototype attribute in Symfony 2 forms

Starting with umpteens days, I am blocking the issue with Symfony 2 and forms.

I got a website form. "Websites" is a collection of websites, and each website contains two attributes: "type" and "URL".

If I want to add more than one website to my database, I can click the "Add another website" link, which will add another line of the website to my form. Therefore, when you click the Submit button, you can add one or X website at a time.

In this process, the data-prototype attribute is used to add a string, which can generate a sub-form of the site.

The problem is that I am customizing my form to have excellent graphic rendering ... for example:

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

But the data prototype does not care about this setting, with tags and HTML and CSS properties. I keep rendering 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> 

Does anyone have an idea to do this hack?

+47
collections forms symfony
Sep 26 '11 at 13:20
source share
11 answers

A bit outdated, but this is a deadly simple solution.

The idea is to simply visualize the elements of the collection through the Twig template, so you have full opportunity to customize the prototype, which will be placed in the data-prototype="..." tag. As if it were an ordinary, ordinary form.

In yourMainForm.html.twig file:

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

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

Credit: adapted from https://gist.github.com/tobalgists/4032213

+67
Jan 26 '14 at 13:52
source share

I know this question is quite old, but I had the same problem, and that is how I loved it. I use the macro twig to accomplish this. Macros are similar to functions, you can display them with different arguments.

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

Now you can display this macro wherever you want. Note that information_prototype() is just a macro name, you can name it whatever you want. If you want to use a macro to display data and a prototype in the same way, do the following:

 <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 contains the prototype data of the form with the specified prototype_name . Use _self.+macroname if you want to use the macro in the same template.

You can learn more about macros in the Twig documentation.

+44
Jul 26 '13 at 7:27
source share

You probably learned about this, but here is a solution for others.

Create a new template and copy / paste this code into it: https://gist.github.com/1294186

Then, in the template containing the form you want to customize, apply it to your form by doing the following:

 {% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %} 
+25
Mar 03 2018-12-12T00:
source share

I know that the answer is very late, but it can be useful for visitors.

in your theme file, you can simply use one block to render each collection of website widget elements as follows:

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

also create a theme block for your collection widget as follows:

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

Now the prototype and the recorded collection will be the same.

+5
Aug 29 '15 at 6:38
source share

I recently encountered a similar problem. Here, how you can override the prototype of a collection without explicitly specifying in 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 } }) }} 

You can do whatever you want, then in your custom thread. For example:

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

Useful when you only need to do this in certain places and not need a global redefinition that applies to all collections.

+5
Oct. 14 '15 at 15:07
source share

I had a somewhat similar problem. You may need to tweak this to work for your business, but someone may be helpful.

Create a new template file to save your own theme theme

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

You can usually use the form_row function to display field labels, errors, and widgets. But in my case, I just wanted to display the widget. As you say, using the data prototype function also displays a label, so in our new fields.html.twig files, enter your code for how you want the field to look:

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

I deleted the div container, label and error and just left the widget.

Now in the twig file that displays the form, just add this after {% extends ...%}

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

And now form_widget (form.yourVariable.var.prototype) will only display the field and nothing else.

+2
Mar 28 '13 at 22:08
source share

Applied widescreen topics will be applied to the prototype. See Deploying Applications in General

+1
Sep 26 2018-11-11T00:
source share

Here is a sample code for custom data prototypes:

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

where emails is your collection.

+1
Nov 10 '11 at 18:57
source share

To set up various prototypes of VS elements of an existing collector, you can override collection_widget as follows:

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

And then in your user record:

 {% block _myCollection_entry_row %} {% if(inPrototype is defined) %} {# Something special only for prototype here #} {% endif %} {% endblock %} 
0
Jan 23 '17 at 14:26
source share

If you do not need to define a template throughout the system, just install the template in the branch template and ask him to use it.

 {# 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> 
0
Sep 27 '17 at 20:53 on
source share

This post focuses on the use of pre-existing conventions in the branch template.

Based on the “How to Insert a Collection of Forms” from the Symfony Cookbook ( http://symfony.com/doc/master/cookbook/form/form_collections.html ), you can simply enter any form of html_escaped data that you want to use in the prototype data (it can be considered a hack, but it works great), and only pages using this template will change.

In this example, they tell you:

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

This can be successfully replaced with something like:

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

If the attribute of the data type of the table with the above class tags is a version with html-escaping (and the rows deleted are deleted, although spaces are in order and required):

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

... but you must also configure javascript in the example to add tr instead of li elements:

 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); ... 

For me, the next step is to figure out how to define a prototype in an external file, which I can somehow call in the branch template for a data prototype that dynamically works with the form. Something like:

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

So, if one of the other posts describes this, and I'm too tight, or if someone knows how to do this, say so!

There is a link to something from Francois gitHub, but I have not seen any explanation, so I think this is probably the more dynamic method that I will receive in one of these coming days.

World Steve

Update:

You can also use only parts of the prototype:

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

If the attribute of the data type of the table with the above class tags is a version with html-escaping (and the rows deleted are deleted, although spaces are in order and required):

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

(I used http://www.htmlescape.net/htmlescape_tool.html .)

Symfony will replace the information between the {{}} html_escaped window (due to the "| e" field) when the page is displayed. Thus, any setting at the field level is not lost, but! you must manually add and remove fields in the prototype, as you do with an entity :)

-one
Apr 30 '13 at 15:53
source share



All Articles