Validating dynamically loaded choices in Symfony 2
To do the trick you need to overwrite the sub_choice
field before submitting the form:
public function buildForm(FormBuilderInterface $builder, array $options){ ... $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $parentChoice = $event->getData(); $subChoices = $this->getValidChoicesFor($parentChoice); $event->getForm()->add('sub_choice', 'choice', [ 'label' => 'Sub Choice', 'choices' => $subChoices, ]); });}
this accept any value
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $data = $event->getData(); if(is_array($data['tags']))$data=array_flip($data['tags']); else $data = array(); $event->getForm()->add('tags', 'tag', [ 'label' => 'Sub Choice', 'choices' => $data, 'mapped'=>false, 'required'=>false, 'multiple'=>true, ]);});
Adding an alternate approach for future readers since I had to do a lot of investigation to get my form working. Here is the breakdown:
- Adding a "New" option to a dropdown via jquery
- If "New" is selected display new form field "Custom Option"
- Submit Form
- Validate data
- Save to database
jquery code for twig:
$(function(){ $(document).ready(function() { $("[name*='[custom_option]']").parent().parent().hide(); // hide on load $("[name*='[options]']").append('<option value="new">New</option>'); // add "New" option $("[name*='[options]']").trigger("chosen:updated"); }); $("[name*='[options]']").change(function() { var companyGroup = $("[name*='[options]']").val(); if (companyGroup == 'new') { // when new option is selected display text box to enter custom option $("[name*='[custom_option]']").parent().parent().show(); } else { $("[name*='[custom_option]']").parent().parent().hide(); } });});// Here's my Symfony 2.6 form code: ->add('options', 'entity', [ 'class' => 'Acme\TestBundle\Entity\Options', 'property' => 'display', 'empty_value' => 'Select an Option', 'mapped' => true, 'property_path' => 'options.optionGroup', 'required' => true,])->add('custom_option', 'text', [ 'required' => false, 'mapped' => false,])
To handle the form data we need to use the PRE_SUBMIT form event.
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $data = $event->getData(); $form = $event->getForm(); if (isset($data['options']) && $data['options'] === 'new') { $customOption = $data['custom_option']; // todo: handle this better on your own if (empty($customOption)) { $form->addError(new FormError('Please provide a custom option')); return; } // Check for a duplicate option $matches = $this->doctrine->getRepository('Acme\TestBundle\Entity\Options')->matchByName([$customOption]); if (count($matches) > 0) { $form->addError(new FormError('Duplicate option found')); return; } // More validation can be added here // Creates new option in DB $newOption = $this->optionsService->createOption($customOption); // return object after persist and flush in service $data['options'] = $newOption->getOptionId(); $event->setData($data); }});
Let me know if ya'll have any questions or concerns. I know this might not be the best solution but it works. Thanks!