kuvoc
kuvoc

Reputation: 11

How to validate depending on the selected value?

I have a simple form:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('name', null, ['required' => true])
        ->add('doYouWant', ChoiceType::class, ['choices' => ['no' => 'no', 'yes' => 'yes']])
        ->add('type')
    ;
}

I would like the user after the selection doYouWant to "yes" to have a mandatory "type" option, so I am trying:

   $builder->addEventListener(
        FormEvents::PRE_SUBMIT,
        function (FormEvent $event) use ($builder) {
            $data = $event->getForm()->getData();

            if ($data['doYouWant'] == 'yes') {
                $builder->add('type', null, ['required' => true]);
            }

        }
    );

But it does not matter...

Upvotes: 1

Views: 1535

Answers (2)

Dan Costinel
Dan Costinel

Reputation: 1736

I think the simplest way would be to add constraints to each field from your type, and then, in template, by using jquery you can toggle the visibility of your type field based on the selected value from the dropdown.

# AppBundle/Form/ExampleType.php
$builder
    ->add('name', null, [
        'constraints' => [
             new NotBlank(['message' => 'This cannot be empty']),
        ]
    ])
    ->add('doYouWant', ChoiceType::class, [
        'placeholder' => 'Select',
        'choices' => ['no' => 'No', 'yes' => 'Yes'],
        'constraints' => [
            new NotBlank(['message' => 'This cannot be empty']),
        ]
    ])
    ->add('type', EmailType::class, [
        'constraints' => [
            new NotBlank(['message' => 'This cannot be empty']),
            new Email([
                'message' => "The email '{{ value }}' is not a valid email",
            ])
        ]
    ])
;

I've added the type field as being of type email, just for testing purposes.

# Controller/DefaultController.php
/**
 * @param Request $request
 * @Route("/test", name="test")
 * @return Response
 */
public function testAction(Request $request) : Response
{
    $form = $this->createForm(ExampleType::class);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        dump($form->getData());die;
    }

    return $this->render('default/test.html.twig', [
        'form' => $form->createView(),
    ]);
}


# default/test.html.twig (assuming you are using bootstrap and jquery)
{% block body %}
<div class="container">
    <div class="row">
        <div class="col-xs-12">
            {{ form_start(form, { attr: { 'novalidate': 'novalidate' } }) }}
                <div class="form-group">
                    {{ form_label(form.name) }}
                    {{ form_widget(form.name,{ attr:{ class:'form-control' } }) }}
                    {{ form_errors(form.name) }}
                </div>
                <div class="form-group">
                    {{ form_label(form.doYouWant) }}
                    {{ form_widget(form.doYouWant,{ attr:{ class:'form-control' } }) }}
                    {{ form_errors(form.doYouWant) }}
                </div>
                <div class="form-group type hidden">
                    {{ form_label(form.type) }}
                    {{ form_widget(form.type,{ attr:{ class:'form-control' } }) }}
                    {{ form_errors(form.type) }}
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-primary">Send</button>
                </div>
            {{ form_end(form) }}
        </div>
    </div>
</div>
{% endblock %}

{% block javascripts %}
<script>
    $(document).ready(function(){
        $('#appbundle_example_doYouWant').change(function(){
            var choice = $(this).val();
            if (choice == 'Yes') {
                $('.type').removeClass('hidden');
            } else {
                $('.type').addClass('hidden');
            }
        });
    });
</script>
{% endblock %}

Upvotes: 1

iamjc015
iamjc015

Reputation: 2237

You can use validation groups and put your assertions inside your entity.

And then you can choose validation groups based on the submitted data like so:

https://symfony.com/doc/current/form/data_based_validation.html

How to add assertion on entity:

class MyEntity {

    /**
     * @Assert\NotBlank(groups={"YourGroup"})
     */
    protected $type;

}

Then on your form:

public function configureOptions(OptionsResolver $resolver)
{
  $resolver->setDefaults(array(
      'validation_groups' => function (FormInterface $form) {
              $data = $form->getData();

              $want = $data->getDoYouWant();

              if ($want) {
                  return ['YourGroup'];                   
              }

              return ['Default'];  
            },
    ));
}

Upvotes: 0

Related Questions