Symfony Twig настраивает индивидуальное поле для коллекции

В документации есть способ в Symfony настроить Отдельное поле, основанное на имени/идентификаторе виджета.

{% form_theme form _self %}

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

{{ form_widget(form.name) }}

Здесь фрагмент _product_name_widget определяет шаблон, используемый для поля с идентификатором product_name (и name — product[name]).

Это работает для обычного виджета, но не для виджета внутри коллекции. Из-за лишних столбцов. Как это:

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

Как заставить работать настройку Twig внутри коллекции?

Я думал что-то вроде этого, но это не работает:

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

Не работает даже следующее:

{% _productbundle_product_type_foobar_1_value_widget %}

Как заставить его работать?


person user2382765    schedule 18.06.2013    source источник
comment
И если вы используете {% block _productbundle_product_type_foobar_1_{{ db.name }}_widget %}_1_)   -  person cheesemacfly    schedule 18.06.2013
comment
нет, также не работает следующее: {% _productbundle_product_type_foobar_1_value_widget %}   -  person user2382765    schedule 18.06.2013
comment
Я удивлен, потому что в документе говорится: Here, the _product_name_widget fragment defines the template to use for the field whose id is product_name (and name is product[name]). Итак, если имя вашего виджета productbundle_product_type[foobar][1][value], вы должны иметь возможность использовать {% block _productbundle_product_type_foobar_1_value_widget %}   -  person cheesemacfly    schedule 18.06.2013
comment
Документы ссылаются на «обычные» form_widgets, я думаю, а не на form_widgets в коллекции. Но действительно, это странно. Вот почему я задаю вопрос. :-)   -  person user2382765    schedule 18.06.2013


Ответы (3)


Пару вечеров назад я работал над проектом и столкнулся именно с этой проблемой - решение, которое я нашел, представляет собой пару блоков, которые выглядят следующим образом (без кода, специфичного для проекта):

{# 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 %}
person ptlis    schedule 18.06.2013
comment
«Метод inner_widget не существует». Метод внутренний_виджет. Каким должно быть имя My_collection_widget? _productbundle_product_type_foobar_widget не работает. Думаю, он не соответствует требованиям, которые мне нужны. - person user2382765; 19.06.2013
comment
Замените «my_collection» в обоих блоках на имя коллекции в форме, которую вы отображаете. Внутри блока *item_widget вы предоставляете пользовательскую разметку для одного элемента в коллекции; если ваша коллекция проста (один тип), просто вызовите {{ form*(prototype) }} с любой пользовательской разметкой, которую вы хотите. Если коллекция более сложная (каждый элемент коллекции содержит несколько типов), то в приведенном выше примере показано, как настроить каждый встроенный тип. - person ptlis; 19.06.2013
comment
Где не на той же странице, я думаю :-) Я просто показываю коллекцию, без возможности добавить больше. $builder ->add('foobar', 'collection', array( 'type' => new ProductbundleProductType(), )); - person user2382765; 19.06.2013
comment
Принцип должен быть тот же; если ProductbundleProductType простой (например, расширение типа), то должен работать код в верхней части my_collection_item_widget, если он более сложный, то должно работать повторение кода в нижней части блока (замена inner_widget на имя каждого типа внутри ProductbundleProductType). - person ptlis; 19.06.2013

Я знаю, что это старый вопрос, но, возможно, люди все еще сталкиваются с этим. Это объясняется именованием фрагментов для коллекций.

В этих случаях вы используете _entry_ вместо номера элемента коллекции. Используйте инструкции по ссылке для именования фрагментов, но это может отличаться. Иногда «тип» является частью имени фрагмента, иногда первая буква в верхнем регистре, иногда в нижнем регистре и т. д. Я бы использовал инструмент разработчика браузера, чтобы найти фактическое имя, чтобы убедиться. Вы также можете настроить используемые имена, добавив функцию getBlockPrefix в класс формы.

Поэтому в приведенном выше случае настроенный блок может выглядеть примерно так:

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

Где «поле» будет именем поля в элементе вашей коллекции.

person tlarson    schedule 20.08.2019

Несколько вещей здесь:

<сильный>1. Ошибка документации

документация немного отличается от CamelCase. сущности. Для 5.3 должно быть: _taskManager_taskLists_entry_widget (вместо _task_manager_task_lists_entry_widget)

Вы можете подтвердить название, сбросив форму или поле формы: {{ dump(form) }} или {{ dump(form.yourField) }} в свой шаблон, а затем найдите unique_block_prefix в разделе vars.

<сильный>2. НЕ используйте переопределения блоков, макросы намного проще

Это делает вещи абсолютно более сложными, чем необходимо. Просто определите макрос:

{% import _self as formMacros %}
{% macro formatCollection(form) %}
    <div class="form-group row">
        <div>
            {{ form_widget(form.field1) }}
            {{ form_widget(form.field2) }}
            {{ form_widget(form.field3) }}
        </div>
    </div>
{% endmacro %}

затем просто запустите его для каждой коллекции:

{% for item in form.collectionItems %}
    {{ formMacros.formatCollection(item) }}
{% endfor %}

<сильный>3. Прототип

Получите прототип перед визуализацией поля коллекции. Вы можете сохранить его в переменной.

{% set prototype = form.collection.vars.prototype %}

Затем просто визуализируйте его, когда захотите, используя наш макрос:

<div data-js="collection" data-prototype="{{ formMacros.formatCollection(prototype)|e('html_attr') }}">
person ptmr.io    schedule 26.07.2021