我想创建一个依赖选择框:如果选择第一个选择框,则应填充第二个选择框。
我的第一个选择框未映射到模型。我使用
$form->get('emailTemplateBlockType')->setData($emailTemplateBlockType)
在控制器中手动设置值。如何在表单事件中使用此数据来创建第二个选择框?
$builder
->add('emailTemplateBlockType', 'entity', array(
'class' => 'MbDbMVibesBundle:EmailTemplateBlockType',
'property' => 'name',
'mapped' => false,
'empty_value' => 'Choose a block type',
'attr' => array(
'class' => 'emailTemplateBlockTypeSelect',
)
))
->add('save', 'submit');
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
echo "name: ".$form->get('emailTemplateBlockType')->getData()->getName();
die;
});
我有一个带有 jQuery 的 onChange 事件,它将第一个选择框的选择再次发送到我的前端控制器。然后,前端控制器再次创建表单,但这次添加了第一个选择框的值。但由于它不是提交,我认为使用 POST_SUBMIT 事件也不起作用。
我的控制器的片段:
$form = $this->createForm(new EmailTemplateSiteEmailTemplateBlockType(), $entity, array(
'action' => $this->generateUrl('_email_tpl_site_block_edit', array(
'emailTemplateSiteId' => $emailTemplateSiteId,
'emailTemplateSiteBlockId' => $emailTemplateSiteBlockId,
))
));
if ($request->request->get('blockTypeId')) {
$this->get('logger')->debug('setting block type');
$emailTemplateBlockType = $em->getRepository('MbDbMVibesBundle:EmailTemplateBlockType')
->find($request->request->get('blockTypeId'));
if ($emailTemplateBlockType)
$form->get('emailTemplateBlockType')->setData($emailTemplateBlockType);
else
throw new $this->createNotFoundException('Cannot find blocktype with id '.$request->request->get('blockTypeId'));
}
$form->handleRequest($request);
我想我终于成功了。我将在这里描述我的陷阱,有关我最终如何实现这一点的完整文章,请参阅Symfony2中的表单:依赖选择框
首先,看来我必须提交完整的表单才能触发表单事件 PRE_SUBMIT。我不能只将一个变量发布到表单中。
其次,我完全错过了 PRE_SUBMIT 事件中的数据存储在数组中而不是对象中,这实际上在这篇文章中得到了完美的提及。所以我应该使用:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($addEmailTemplateBlock) {
$form = $event->getForm();
$data = $event->getData();
if (array_key_exists('emailTemplateBlockType', $data)) {
$addEmailTemplateBlock($form, $data['emailTemplateBlockType']);
}
});
第三是我的未映射表单元素无法在 PRE_SET_DATA 中访问,但可以在 POST_SET_DATA 中访问。
第四是,如果我已经选择了第一个和第二个选择框,那么当我更改第一个选择框时,我会遇到问题。这是有道理的,因为如果第一个选择框发生变化,第二个选择框中的值确实会无效。解决此问题的最简单方法是在第一个选择框的更改事件中将值设置为空。
我还想指出,当您添加更多依赖字段时,这种方法不需要在控制器或 JavaScript 中编写任何额外的脚本。所有逻辑都是在表单构建器内完成的,因此我认为它创建了比 Airam 方法更好的可重用代码。
我写了这个小的静态方法:
public static function getUnmappedData($form): array
{
$fields = array_filter($form->all(), function($field)
{
$config = $field->getConfig();
$options = $config->getOptions();
$zval = (true == $options['mapped']);
return($zval);
});
$zval = array_map(function($field)
{
$zval = $field->getData();
return($zval);
}, $fields);
return($zval);
}