我正在使用事件侦听器来动态修改表单。我想为动态添加的字段添加另一个事件监听器。我不知道如何做到这一点。
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
}
我只是使用$builder
函数中的buildForm
来将事件监听器添加到second_field
但是因为在最初生成表单时该字段不存在会抛出错误
如果我尝试通过执行以下操作在第一个事件侦听器中添加新的事件侦听器:
$form->get('second_field')->addEventListener(...)
然后我收到错误:
Call to undefined method Symfony\Component\Form\Form::addEventListener()
欢迎任何建议。
答案 0 :(得分:9)
如果,实际上是。
FormInterface没有addEventListener方法,但FormBuilderIntreface拥有它。如果要添加任何侦听器,则应按表单构建器创建表单字段。
例如:
// 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());
答案 1 :(得分:2)
我刚刚花了一半的工作时间在这方面苦苦挣扎。我正在使用symfony 3.2.x,帮助我的最好的事情是this answer。
我有一个三重依赖(国家,州,地区,邮政编码)我已经解决了所有相同的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);
}
这些函数中的每一个都处理一个动态字段,它们都是如下所示:
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);
});
}
只需更改其他两个函数的实体引用:cityAjaxFieldFormListener和zipCodeAjaxFieldFormListener
答案 2 :(得分:0)
您实际上不需要将事件侦听器添加到first_field
或second_field
本身。您可以将事件侦听器保留在父窗体上,并检查提交的和设置的数据是否包含first_field
的数据。如果是,请添加second_field
。在同一个侦听器中,检查数据是否已设置或提交到second_field
。如果有,请添加第三个字段。
此处的文档中概述了类似的概念:http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data