【问题标题】:Access unmapped form data in form event在表单事件中访问未映射的表单数据
【发布时间】:2015-01-04 10:35:40
【问题描述】:

我想创建一个依赖选择框:如果第一个选择框被选中,第二个选择框应该被填充。

我的第一个选择框没有映射到模型。我使用$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);

【问题讨论】:

  • 您是否尝试过将该事件绑定到POST_SUBMIT
  • 是的,我刚试过.. 不起作用,因为我没有提交重新加载表单。也许我应该编辑我的问题。
  • @rolandow:使用 PRE_SUBMIT 事件,你会得到原始数据。

标签: symfony symfony-forms


【解决方案1】:

我想我终于成功了。我将在这里描述我的陷阱,有关我最终如何实现这一点的完整文章请参阅Forms in Symfony2: dependent selectboxes

首先,看来我必须提交完整的表单才能触发表单事件 PRE_SUBMIT。我不能只在表单中发布一个变量。

其次,我完全错过了在 PRE_SUBMIT 事件中,数据存储在数组而不是对象中,这实际上在 this post 中被完美地提及。所以我应该使用:

$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 的方法创建了更好的可重用代码。

【讨论】:

    【解决方案2】:

    我写了这个小的静态方法:

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-19
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      • 1970-01-01
      • 2015-02-27
      • 2020-03-01
      • 1970-01-01
      相关资源
      最近更新 更多