Conditionally enable form type in Symfony 2/3

329 Views Asked by At

I have 2 form type that display 2 selects

    $builder
        ->add('control1', EntityType::class, [
            'label' => 'Country',
            'class' => Country::class,
        ])
        ->add('control2', EntityType::class, [
            'label' => 'State',
            'class' => State::class,
        ])

then in the twig template

        {{ form_row(form.control1)}}
        {{ form_row(form.control2)}}

How can I enable control2 only if a specific option is selected in control 1? thanks.

1

There are 1 best solutions below

0
Reqven On

Dynamic Generation for Submitted Forms

You want to customize the form specific to the data that was submitted by the user. For example, imagine you have a registration form for sports gatherings. Some events will allow you to specify your preferred position on the field. This would be a choice field for example. However, the possible choices will depend on each sport. You will need the correct options in order for validation to pass.

The following example create a form with two fields, country and state. The state field depends on the country field and will remain disabled with no choices available if no country has been selected.

Form Type

namespace AppBundle\Form;

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Doctrine\ORM\EntityManagerInterface;
use AppBundle\Entity\Country;
use AppBundle\Entity\State;

class CountryStateType extends AbstractType
{
  private $entityManager;
  private $countryRepository;
  private $stateRepository;

  public function __construct(EntityManagerInterface $entityManager)
  {
    $this->entityManager     = $entityManager;
    $this->countryRepository = $entityManager->getRepository(Country::class);
    $this->stateRepository   = $entityManager->getRepository(State::class);
  }
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder->add('country', EntityType::class, [
      'class' => Country::class,
      'placeholder' => 'Select',
      'choice_label' => 'name',
      'label' => 'Country'
    ]);

    $formModifier = function (FormInterface $form, $countryId = null) {
      $country  = null === $countryId ? null : $this->countryRepository->find($countryId);
      $states   = null === $country ? [] : $this->stateRepository->findAll();
      $disabled = null === $country ? true : false;

      $form->add('state', EntityType::class, [
        'class' => State::class,
        'placeholder' => 'Select',
        'choice_label' => 'name',
        'label' => 'State',
        'choices' => $states,
        'disabled' => $disabled
      ]);
    };

    $builder->addEventListener(
      FormEvents::PRE_SET_DATA,
      function (FormEvent $event) use ($formModifier) {
        $data = $event->getData();
        $data = null === $data ? [] : $data;
        $countryId = array_key_exists('country', $data) ? $data['country'] : null;

        $formModifier($event->getForm(), $countryId);
      }
    );

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

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

Template

{{ form_start(form) }}         
  {{ form_widget(form.country) }}
  {{ form_widget(form.state) }}
  <button type="submit">Submit</button>
{{ form_end(form) }}

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
  var $country = $('#{{ form.country.vars.id }}');
  $country.change(function () {
    var $form = $(this).closest('form');
    var data = {};
    data[$country.attr('name')] = $country.val();

    $.ajax({
      url: $form.attr('action'),
      type: $form.attr('method'),
      data: data,
      success: function (html) {
        $('#{{ form.state.vars.id }}').replaceWith(
          $(html).find('#{{ form.state.vars.id }}')
        );
      }
    });
  });
</script>