【问题标题】:How to structure Symfony to check for `onChange` dropdown fields?如何构建 Symfony 以检查“onChange”下拉字段?
【发布时间】:2016-02-28 06:34:16
【问题描述】:

在我的示例中,我有四个实体要用于博客平台:Owner Post User Location

  • 一个所有者可以有多个帖子
  • 一个帖子可以有多个用户位置

我正在尝试创建一个管理表单,我可以在其中从下拉菜单中选择 Owner,这将刷新表单 onChange 以填充 Posts的下拉菜单>。

当一个 Post 被选中时,表单再次刷新,表单字段 UsersLocations 与该帖子相关联。然后我可以:

  1. 使用更多信息(例如用户的出生日期或位置的 GPS 坐标)更新现有实体
  2. 创建任一实体的新实例以附加到 Post

我没有包含 Location 实体,也没有包含命名空间/包含语句,因为它们会影响我的主要问题,即如何在控制器/表单类型中编码这样的管理页面(我的尝试如下):

控制器:

/**
* @Route("/adminposts", name="admin_posts")
*/
public function updatePostsAction(Request $request)
{
  $user = new User();
  $form = $this->createForm(new UserType(), $user);
  $form->handleRequest($request);

  if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($owner);
        $em->persist($post);
        $em->persist($user);
        $em->persist($location);
        $em->flush();
        return $this->redirectToRoute('homepage');
  }
  return $this->render('AppBundle:Default:adminupdate.post.html.twig', array(
        'form' => $form->createView(),
  ));
}

用户表单类型:

class UserType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
        $builder
             ->add('owner','entity',array(
                  'class'=>'AppBundle:Owner',
                  'choice_label'=>'username',
                  'query_builder'=>function(EntityRepository $er) {
                        return $er->createQueryBuilder('d')
                             ->orderBy('d.username','ASC');
                  }))

             ->add('post','entity',array(
                  'class'=>'AppBundle:Post',
                  'choice_label'=>'posttext',
                  'query_builder'=>function(EntityRepository $er) {
                        return $er->createQueryBuilder('d')
                             ->orderBy('d.postdate','ASC');
                  }))

             ->add('Firstname')
             ->add('Surname')
             ->add('DOB')
             ->getForm();
  }

  public function configureOptions(OptionsResolver $resolver)
  {
        $resolver->setDefaults(array(
             'data_class' => 'AppBundle\Entity\Users',
        ));
  }

  public function getName()
  {
        return 'user';
  }
}

【问题讨论】:

  • 我建议你使用Ajax,你试过了吗?
  • 感谢@Delphine,在开始使用 Symfony 之前我曾尝试过 Ajax - 老实说,我不确定如何在 Symfony 中使用 OO 框架和 twig 模板来实现 Ajax。你能指出我正确的方向吗?

标签: forms symfony doctrine-orm entity


【解决方案1】:

好的,也许你可以看看这里:Symfony2: Change choices with ajax and validation 或者按照我的方法:

在您的用户类型中:

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('owner','entity',array(
                'class'=>'AppBundle:Owner',
                'choice_label'=>'username',
                'query_builder'=>function(EntityRepository $er) {
                    return $er->createQueryBuilder('o')
                        ->orderBy('o.username','ASC');
                }))

            ->add('Firstname')
            ->add('Surname')
            ->add('DOB');

        // Add listeners for Post field
        $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
        $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
    }


    protected function addElements(FormInterface $form, $owner = null)
    {
        if($owner){
            $form->add('post','entity',array(
                'class'=>'AppBundle:Post',
                'choice_label'=>'posttext',
                'query_builder'=>function(EntityRepository $er, $owner) {
                    return $er->createQueryBuilder('p')
                        ->join('p.owner', 'o')
                        ->where('o.id = :ownerID')
                        ->setParameter('ownerID', $owner->getID() )
                        ->orderBy('d.postdate','ASC');
                }));
        }
        else{
            $form->add('post','choice',array(
                'choice_label'=>'posttext',
                'empty_value' => '-- Choose --',
                'choices' => array())
            );
        }
    }

    public function onPreSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();

        $this->addElements($form, $data->getOwner());
    }

    public function onPreSetData(FormEvent $event)
    {
        /** @var User user */
        $user = $event->getData();
        $form = $event->getForm();

        $this->addElements($form, $user->getOwner());
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Users',
        ));
    }

    public function getName()
    {
        return 'user';
    }
}

我假设你知道如何在 jQuery 中创建一个 onChange 事件(我曾经使用它)和一个 ajax 调用。

在你看来,只是为了提醒:

 {{ form_row(
        form.owner,
        {
            'attr': {               
                'data-owner-id': ""~form.owner.vars.id,
                'class': "change-posts-per-owner",
            }
        }
    ) }}
    {{ form_row(form.post) }}
    {{ form_row(form.firstname) }}
    {{ form_row(form.surname) }}
    {{ form_row(form.DOB) }}

还有你的 Ajax 脚本:

   $(document).on('change', 'select .change-posts-per-owner', function(){

       var ownerID = $(this).data("owner-id");

       $.ajax({
         url:  your_url,
         type: "GET", //or POST
         data: 'ownerID='+ownerID,
         dataType: 'JSON', //or html or whatever you want
         success:function(data) { 
          //Replace <option element in your select element for post list considering your dataType (type of response)
         }
      });

    }

您也可以使用$.post()$.get() 代替显式方法$.ajax(); 我建议您使用 FOSJSRoutingBundle 通过Routing.generate() 方法指示您的网址。

【讨论】:

  • 感谢您提供如此详尽的回答 :) 我可以在周末尝试一下并回复您!
  • 嗨@Delphine,我已经按照您的代码进行了操作,我认为一切正常,只是我不确定如何构造success:function(data) {} 部分的内容?此外,查看您发送的另一个问题的链接 - 看起来它似乎不需要 Ajax 和 onChange 事件 - 如果是这样,那会是一个更简单的 Symfony 替代方案吗?
  • 在@Delphine (symfony.com/doc/current/cookbook/form/…) 的引导下,我一直在研究 Symfony 文档中的 FormEvents - 但是似乎我们应该全部 all 用户在响应中的帖子。但是,由于每个用户可以拥有数千个帖子,因此与选择用户后仅获取所需数据相比,这似乎有点过头了?
  • 在您的 Ajax 调用中,您应该传递 ownerID(在第一次选择中被选中的那个人)。这就是我的代码感谢$user-&gt;getOwner()
  • 而且,ajax 方法应该返回一个 Posts 数组(归您选择的所有者所有)。您还应该为此使用 Json 格式。在您的控制器(调用 ajax 方法)中,只需获取与所有者相关的帖子即可。返回一个 Json 响应:return new JsonResponse($posts) 所以在你的成功 ajax 部分中只做:$.each(data, function(k, v) { $(child).append('&lt;option value="' + v[itemKey] + '"&gt;' + v[itemLabel] + '&lt;/option&gt;'); } 其中 child 是第二个选择框。 PreSubmit 事件将通过将这些帖子添加到表单来验证表单。
猜你喜欢
  • 2023-03-29
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-31
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多