Search code examples
symfonytwigsymfony4formbuildersylius

Symfony form builder: How to iterate/render dynamic amount of text fields in twig? (Sylius - exta checkout step)


I added an extra checkout step to the Sylius checkout procedure and I am trying to add 1 text field per instance of an ordered item. Thus having put 3x itemA and 1x itemB in cart should spawn 4 text fields.

I have this code so far in the form builder (based on code from here: https://sf.khepin.com/2011/08/basic-usage-of-the-symfony2-collectiontype-form-field/)

        $builder->add('myCollection', CollectionType::class, $formOptions);

        $totalCounter = 0;
        /** @var OrderItem $item */
        foreach($order->getItems() as $item) {
            for($itemCounter = 0 ; $itemCounter < $item->getQuantity(); $itemCounter++ ) {
                $totalCounter++;
                $builder->get('myCollection')->add('item_' . $totalCounter, TextType::class, $formOptions);
            }
        }

First Question: Is this the right approach for the form builder for my particular scenario, and secondly: If yes, how do I read from this in the twig template?

form.children.myCollection does exist but does not seem to contain these children, so that I could use them with the form_row function. What I would have expected is something like this:

{% set totalCounter = 0 %}
{% for item in order.items %}
    {% for itemCounter in 1..item.quantity %}
        {% set totalCounter = totalCounter + 1 %}
        {{  form_row(form.children.myCollection['item_' ~ totalCounter ]) }}
    {% endfor %}
{% endfor %}

Any idea how to do this? Thanks for any hint in advance!


Solution

  • Just saw my exact case is described in the beginning of the documentation of CollectionType https://symfony.com/doc/current/reference/forms/types/collection.html

    The form builder part..

    $builder->add('emails', CollectionType::class, [
        // each entry in the array will be an "email" field
        'entry_type' => EmailType::class,
        // these options are passed to each "email" type
        'entry_options' => [
            'attr' => ['class' => 'email-box'],
        ],
    ]);
    

    ..and the twig part:

    {{ form_label(form.emails) }}
    {{ form_errors(form.emails) }}
    
    <ul>
    {% for emailField in form.emails %}
        <li>
            {{ form_errors(emailField) }}
            {{ form_widget(emailField) }}
        </li>
    {% endfor %}