问题
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.
回答1:
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());
回答2:
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
回答3:
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