Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony Twig customize an Individual field for a collection

Tags:

twig

symfony

In the documentation there is a way in Symfony to customize a Individual field, based on the name/id of the widget.

{% form_theme form _self %}

{% block _product_name_widget %}
    <div class="text_widget">
        {{ block('field_widget') }}
    </div>
{% endblock %}

{{ form_widget(form.name) }}

Here, the _product_name_widget fragment defines the template to use for the field whose id is product_name (and name is product[name]).

This works for a normal widget, but not if a widget is inside a collection. Because of the extra columns. Like this:

name="productbundle_product_type[foobar][1][value]" id="productbundle_product_type_foobar_1_value"

What is the way to make the Twig customization work inside the collection?

I thought something like this, but that doesn't work:

{% for db in edit_form.list %}
    {% block _productbundle_product_type_foobar_{{ db.name }}_widget %}
        <div class="text_widget">
            {{ block('field_widget') }}
        </div>
    {% endblock %}
{% endfor %}

Even the following doesn't work:

{% _productbundle_product_type_foobar_1_value_widget %}

What is the way to make it work?

like image 617
user2382765 Avatar asked Jun 18 '13 14:06

user2382765


2 Answers

I was working on a project a couple of evenings ago and encountered precisely this problem - the solution I found is a pair of blocks that look like this (stripped of project-specific code):

{# Collection markup #}
{% block my_collection_widget %}
    {# Customise collection row prototype for allow_add #}
    {% if prototype is defined %}
        {% set data_prototype = block('my_collection_item_widget')  %}
        <div id="my_prototype" data-prototype="{{ data_prototype }}" style="display: none"></div>
    {% endif %}

    {% for prototype in form %}
        {{ block('my_collection_item_widget') }}
    {% endfor %}
{% endblock my_collection_widget %}

{# Collection row markup #}
{% block my_collection_item_widget %}
    {# Collection contains simple, single type #}
    {{ form_errors(prototype) }}
    {{ form_label(prototype) }}
    {{ form_widget(prototype) }}

    {# OR #}

    {# Collection contains a compound type, render child types independantly #}
    {{ form_errors(prototype.inner_widget) }}
    {{ form_label(prototype.inner_widget) }}
    {{ form_widget(prototype.inner_widget) }}
{% endblock my_collection_item_widget %}
like image 98
9 revs Avatar answered Oct 18 '22 08:10

9 revs


I know this is old question, but maybe people still happening upon this. This is explained fragment naming for collections.

You use _entry_ in these cases in place of the collection element number. Use the instructions in the link for fragment naming, but this might vary. Sometimes 'type' is part of the fragment's name, sometimes first letter is upper case, sometimes lower case, etc. I would use a browser developer tool to find the actual name to make sure. You might also be able to customize the names used by adding the getBlockPrefix function to the form class.

Therefore, in your case above, the customized block might look something like:

{% block _ProductBundle_product_entry_widget %}
   <div> {{ form_row(form.field)}} </div>
{% endblock %}

Where 'field' would be the name of a field in the element of your collection.

like image 25
tlarson Avatar answered Oct 18 '22 08:10

tlarson