简体   繁体   中英

Symfony form collection rendering

I'm using symfony 2.3 I have form with field of type "collection"

Visualization code in twig:

{% for field in form.fields %}
    {{ form_row(field.name) }}
{% endfor %}

Everything work, expect when form.fields is empty. Then nothing is visualized in twig loop, witch is fine. But at the end of the form there is "label" for the element "form.fields". Only label.

Workaround:

    {% for field in form.fields %}
        {{ form_row(field.name) }}
    {% endfor %}
    <div class="hidden">
        {{ form_row(form.fields) }}

If there are elements, they will be rendered in the loop. {{ form_row }} will be empty, because all elemets are iterated in the loop above. But if form.fields is empty then there is "hidden" (in the div) label.

What I'm missing !? Why this is happening !?

Hidden div content:

<div class="form-group"><label class="col-sm-2 control-label required">name</label><div class="col-sm-10"><div id="my-id" data-prototype=""></div></div></div>

Builder config:

$builder->add(
    'fieldDataMappers',
    'collection',
    array(
        'type' => new FieldDataType(),
        'allow_add' => true,
        'allow_delete' => true,
        'by_reference' => false,
    )
);

As you have correctly guessed, the Symfony TwigBridge keep track of what is rendered and what is not. This is useful, since there is a function called form_rest(form) , which is especially useful for printing hidden form field, and to prevent the "great jupiter! I forgot to print that field!" moments. :) You often find form_rest at the end of the form, just before the submit button.

Also consider that the collection IS a composite form type, which contains a variable list of child form. When the for loop is not triggered, since the form type is empty, the call to {{ form_row(form.fields) }} print out the collection form type. By default, this will print (you've guessed it) the collection label and an empty div. On the other hand, when the collection is not empty, Symfony will consider the collection as rendered, since all children are already rendered (see FormView::isRendered )

You can take a look into Symfony standard theme form_div_layout.html.twig , especially the blocks form_row (which show label printing) and form_widget_compound (the div and the for loop).

So, if you just need to hide the label (quick and dirty, some div are still there), just use:

$builder->add(
    'fieldDataMappers',
    'collection',
    array(
        'type' => new FieldDataType(),
        'label' => false,
        'allow_add' => true,
        'allow_delete' => true,
        'by_reference' => false,
    )
);

Or better, simply output the whole collection widget, without row:

{{ form_widget(form.fieldDataMappers) }}

Or even better, you print the whole collection with:

{{ form_row(form.fieldDataMappers) }}

...and then add a Twig theme to customize the collection output with something like (note the name syntax, and the missing form_label call):

{% block collection_row -%}
    <div>
        {{- form_errors(form) -}}
        {{- form_widget(form) -}}
    </div>
    <div class="hidden">Something here?</div>
{%- endblock collection_row %}

Hope this help!

{# src/Acme/TaskBundle/Resources/views/Task/new.html.twig #}

{# ... #}

{{ form_start(form) }}
    {# render the task's only field: description #}
    {{ form_row(form.description) }}

    <h3>Tags</h3>
    <ul class="tags">
        {# iterate over each existing tag and render its only field: name #}
        {% for tag in form.tags %}
            <li>{{ form_row(tag.name) }}</li>
        {% endfor %}
    </ul>
{{ form_end(form) }}

{# ... #}

Symfony2 cookbook

http://symfony.com/doc/current/cookbook/form/form_collections.html

Also the field of the collection is named fieldDataMappers not field .

So i think it should be

{% for field in form.fieldDataMappers %}
    {{ form_row(field.name) }}
{% endfor %}
    {{ form_label(form.emails) }}
    <ul id="email-fields-list"
        data-prototype="{{ form_row(form.emails.vars.prototype)|e }}"
        data-widget-tags="{{ '<ol></ol>'|e }}"
        data-widget-counter="{{ form.emails|length }}">
        {% for email in form.emails %}
            <ol>
                {{ form_errors(email) }}
                {{ form_row(email) }}
            </ol>
        {% endfor %}
    </ul>
    <button type="button" class="add-another-collection-widget" data-list-selector="#email-fields-list">Add email</button>
    {{ form_widget(form.emails) }}

I just add {{ form_widget(form.emails) }} after block thant handles adding to collection and no more label on the end of form.

Cheers

I solved this with :

{{ form_label(form.collection) }}
{% for element in form.collection %}
    {{ form_widget(element) }}
{% else %}
    {{ form_widget(form.collection) }}
{% endfor %}

(a bit late, I know, but still a problem with Symfony 5)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM