Dynamically setting Form fields in Symfony

691 views Asked by At

I already tried docs and as you can see in my code I got a country/state example working. But I want to set another field (country code) based in the country, not just the state.

Here is my code, starting with entities:

Address:

<?php

namespace Costo\AddressBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* Address
*
* @ORM\Table()
* @ORM\Entity
*/
class Address
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="address", type="string", length=255)
 */
private $address;

/**
 * @ORM\ManyToOne(targetEntity="Country", inversedBy="addresses")
 */
private $country;

/**
 * @var string
 *
 * @ORM\Column(name="countryCode", type="string", length=255)
 */
private $countryCode;

/**
 * @ORM\ManyToOne(targetEntity="State", inversedBy="addresses")
 */
private $state;

Country:

<?php

namespace Costo\AddressBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* Pais
*
* @ORM\Table()
* @ORM\Entity
*/
class Country
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255)
 */
private $name;

/**
 * @var string
 *
 * @ORM\Column(name="code", type="string", length=255)
 */
private $code;

/**
 * @ORM\OneToMany(targetEntity="State", mappedBy="country")
 */
private $states;

/**
 * @ORM\OneToMany(targetEntity="Address", mappedBy="country")
 */
private $addresses;

And State:

<?php

namespace Costo\AddressBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* Estado
*
* @ORM\Table()
* @ORM\Entity
*/
class State
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255)
 */
private $name;

/**
 * @ORM\ManyToOne(targetEntity="Country", inversedBy="states")
 */
private $country;

/**
 * @ORM\OneToMany(targetEntity="Address", mappedBy="state")
 */
private $addresses;

The Form:

<?php

namespace Costo\AddressBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormInterface;
use Costo\AddressBundle\Entity\Country;

class AddressType extends AbstractType
{
    /**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('address')
        ->add('country');

    $formModifier = function (FormInterface $form, Country $country = NULL) {
        $states = NULL === $country ? array() : $country->getStates();
        $code   = NULL === $country ? '' : $country->getCode();

        $form->add('state', 'entity', array(
            'class' => 'AddressBundle:State',
            'choices' => $states
        ));

        $form->add('countryCode', 'text', array(
            'data' => $code
        ));
    };


    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier){
        //entity
        $data = $event->getData();

        $formModifier($event->getForm(), $data->getCountry());
    });

    $builder->get('country')->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($formModifier){
       $data = $event->getForm()->getData();

       $formModifier($event->getForm()->getParent(), $data);
    });
}

/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Costo\AddressBundle\Entity\Address'
    ));
}

/**
 * @return string
 */
public function getName()
{
    return 'costo_addressbundle_address';
}

}

And Finally my template:

{% extends '::base.html.twig' %}

{% form_theme form 'bootstrap_3_horizontal_layout.html.twig' %}

{% block body -%}
<h3>Add Address</h3>

{{ form_start(form) }}

    {{ form_widget(form) }}

    <div class="form-group">
        <div class="col-sm-2"></div>
        <div class="col-sm-10">
            <input type="submit" class="btn btn-primary btn" value="Aceptar">

            <a href="{{ path('address') }}" class="btn btn-info" role="button">
                <span class="glyphicon glyphicon-list"></span> List</a>
        </div>
    </div>


{{ form_end(form) }}
 {% endblock %}

{% block javascripts %}
{{ parent() }}
<script>
    var $country = $('#costo_addressbundle_address_country');
    // When country gets selected ...
    $country.change(function() {
        // ... retrieve the corresponding form.
        var $form = $(this).closest('form');
        // Simulate form data, but only include the selected country value.
        var data = {};
        data[$country.attr('name')] = $country.val();
        // Submit data via AJAX to the form's action path.
        $.ajax({
            url: $form.attr('action'),
            type: $form.attr('method'),
            data: data,
            success: function(html) {
                // Replace current state field ...
                $('#costo_addressbundle_address_state').replaceWith(
                        // ... with the returned one from the AJAX response.
                        $(html).find('#costo_addressbundle_address_state')
                        );
            }
        });
    });

</script>

{% endblock %}

I would like to set the country code in my address entity,I don't know if the problem is in the form class or it's a problem in the template with the ajax stuff

0

There are 0 answers