I am using event listeners to dynamically modify a form. I want to add another event listener to a field that was added dynamically. Im not sure how to accomplish this.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('first_field','choice',array(
'choices'=>array('1'=>'First Choice','2'=>'Second Choice')
));
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'preSetData'));
$builder->get('first_field')->addEventListener(FormEvents::POST_SUBMIT, array($this, 'postSubmit'));
}
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
$form->add('second_field','choice',array(
'choices'=>array('1'=>'First Choice','2'=>'Second Choice')
));
//Some how add an event listener to this field
}
public function postSubmit(FormEvent $event)
{
$form = $event->getForm()->getParent();
$form->add('second_field','choice',array(
'choices'=>array('1'=>'First Choice','2'=>'Second Choice')
));
//Some how add an event listener to this field
}
I have trie just using the $builder
in the buildForm
function to add the event listener to the second_field
but because the field doesnt exist when the form is initially generated it throws an error.
If i try and add the new event listener inside the first event listener by doing:
$form->get('second_field')->addEventListener(...)
Then i get the error:
Call to undefined method Symfony\Component\Form\Form::addEventListener()
Any suggestions would be welcome.
If, is it actually.
FormInterface does't have the addEventListener method, but FormBuilderIntreface have it. If you want to add any listener, you should to create form field by form builder.
For example:
// create builder for field
$builder = $form->getConfig()->getFormFactory()->createNamedBuilder($name, $type, null, array(
/** any options **/
'auto_initialize'=>false // it's important!!!
));
// now you can add listener
$builder->addEventListener(FormEvents::POST_SUBMIT, $yourCallbackHere)
// and only now you can add field to form
$form->add($builder->getForm());
I have just spent half of my working day struggling on this. I'm using symfony 3.2.x and the best thing that helped me is this answer.
I had a triple dependece (country,state,region,zipcode) i've solved all inside the same FormType:
/** @var EntityManager $em */
private $em;
/**
* GaraFormType constructor.
*
* @param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('country', EntityType::class, array(
'class' => 'Country',
...more attrs
));
$this->stateAjaxFieldFormListener($builder);
$this->cityAjaxFieldFormListener($builder);
$this->zipCodeAjaxFieldFormListener($builder);
}
Each of those functions handles one of the dynamic fields, and they are all the same as follows:
private function stateAjaxFieldFormListener(FormBuilderInterface $builder)
{
$localizationFormModifier = function (FormInterface $form, Country $country = null) {
$stateInCountry = $this->em->getRepository("State")->findBy(array("country" => $country));
if ($form->has('state') && ! $form->isSubmitted()) {
$form->remove('state');
}
$form
->add('state', EntityType::class, array(
'choices' => $stateInCountry,
'class' => 'State',
));
};
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($localizationFormModifier) {
/** @var ClienteTemp $data */
$data = $event->getData();
$country = null !== $data ? $data->getCountry() : null;
$localizationFormModifier($event->getForm(), $country);
});
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($localizationFormModifier) {
$data = $event->getData();
$countryId = array_key_exists('country', $data) ? $data['country'] : null;
$country = $this->em->getRepository("Country")->find($countryId);
$localizationFormModifier($event->getForm(), $country);
});
}
Just change entity references for the other two functions: cityAjaxFieldFormListener and zipCodeAjaxFieldFormListener
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With