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
You don't really need to add the event listener to first_field
or second_field
themselves. You can keep the event listener on the parent form and check both the submitted and the set data for whether or not it includes data for first_field
. If it does, add the second_field
. In the same listener, check if data has been set or submitted to second_field
. If it has, add the third field.
There is a similar concept outlined in the documentation here: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data
来源:https://stackoverflow.com/questions/25354806/how-to-add-an-event-listener-to-a-dynamically-added-field-using-symfony-forms