Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with Form Collection on Symfony2 Beta?

I have an entity User and an entity Address. There is a relation One-to-Many between User and Address :

    class User
    {
        /**
        * @orm:OneToMany(targetEntity="Address")
        */
        protected $adresses;

        [...]

    }

I have a class AddressType, and class UserType :

    class UserType extends AbstractType
    {
        public function buildForm(FormBuilder $builder, array $options)
        {
            $builder->add('addresses', 'collection', array('type' => new AddressType()));

        }

        [...]
    }

In my controller, I build form with :

    $form = $this->get('form.factory')->create(new UserType()); 

... and create view with :

    return array('form' => $form->createView());

I display form field in my twig template with :

    {{ form_errors(form.name) }}
    {{ form_label(form.name) }}
    {{ form_widget(form.name) }}
    [...]

Okay. Now, how to display fields for one or more addresses ? (it's no {{ for_widget(form.adresses.zipcode) }} nor {{ for_widget(form.adresses[0].zipcode) }} ...)

Any ideas ?

like image 236
barbacan Avatar asked May 05 '11 08:05

barbacan


2 Answers

This is how I did it in my form template:

{{ form_errors(form.addresses) }}

{% for address in form.addresses %}
    <div id="{{ 'address%sDivId'|format(loop.index) }}" class="userAddressItem">
        <h5> Address #{{ loop.index }}</h5>

        {{ form_errors(address) }}
        {{ form_widget(address) }}
    </div>
{% endfor %}

And I have a small action bar, driven by jQuery, that lets the user add and remove addresses. It is a simple script appending a new div to the container with the right HTML code. For the HTML, I just used the same output has Symfony but with updated index. For example, this would be the output for the street input text of the AddressType form:

<input id="user_addresses_0_street" name="user[addresses][0][street]" ...>

Then, the next index Symfony will accept is 1 so the new input field you add would look like this:

<input id="user_addresses_1_street" name="user[addresses][1][street]" ...>

Note: The three dots are a remplacement for required="required" maxlength="255" but could change depending on your needs.

You will need more HTML code than that to add a whole new AddressType to the DOM of the browser but this give you the general idea.

Regards,
Matt

like image 171
Matt Avatar answered Oct 26 '22 04:10

Matt


I should top that up with the fact that if you want to dynamically add fields, you need to set the key 'allow_add' to true in your collection field in UserType :

...

$builder->add('addresses', 'collection', array(
    'type' => new AddressType(),
    'allow_add' => true
));

Just spent hours trying to figure out what was missing, and at the time i'm writing the doc does not mention this yet. Hope it'll help fellow developers.

like image 31
flochtililoch Avatar answered Oct 26 '22 04:10

flochtililoch