【问题标题】:Finalizing Symfony2 Dynamic Form Modification完成 Symfony2 动态表单修改
【发布时间】:2013-11-29 05:08:49
【问题描述】:

经过多日试图找出 Symfony to Cookbook 条目... http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

我终于在我的 ProductType.php 文件(见下文)中几乎得到了使用以下代码的第三个示例。

当我添加一个游戏时,当我点击提交按钮时,会出现一个相应的服务器和类别列表。仅当我通过在其中一个字段中输入无效输入来强制出错时,才会显示新字段。

我有两个问题。如果不在 $formModifier 变量中的所有数据都是有效的,它会提交数据并且我看不到“服务器”和“类别”选项。我如何确保需要“服务器”和“类别”,即使在选择游戏之前我不需要它们显示。

第二个问题在食谱条目中,它说“可能仍然缺少一个部分是在选择运动后对表单的客户端更新。这应该通过 AJAX 回调到您的应用程序来处理。在该控制器中,您可以提交表单,但无需处理它,只需使用提交的表单来呈现更新的字段。”

由于我的事件修改器处于“提交”状态,我如何使用所选游戏 (id) 提交到控制器条目,并且只呈现仅在选择游戏后才需要的字段?

提前致谢。

斯科特

<?php

namespace Acme\MainBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\FormInterface;
use Acme\MainBundle\Entity\Game;

class ProductsType extends AbstractType {

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->add('name')
                ->add('price')
                ->add('description')
                ->add('game')

        ;

        // ** Build Form Interface Based On Selected Game **//

        $formModifier = function(FormInterface $form, Game $game, $game_id) {

                    // ** Add Servers Based On Game Id ** // 
                    $form->add('server', 'entity', array(
                        'class' => 'Acme\MainBundle\Entity\GameServers',
                        'query_builder' => function(EntityRepository $er) use ($game_id) {
                            $query = $er->createQueryBuilder('i')
                                    ->select(array('i'))
                                    ->where('i.game_id = :game_id')
                                    ->setParameter('game_id', $game_id)
                                    ->orderBy('i.name', 'ASC');
                            return $query;
                        },
                            )
                    );
                    // ** Build Category List Based on Game Id Submitted ** //
                    // Refactor this so that is nothing is selected that it Doesn't Build Category List **/        
                    $form->add('category', 'entity', array(
                        'class' => 'Acme\MainBundle\Entity\GameCategories',
                        'query_builder' => function(EntityRepository $er) use ($game_id) {
                            $query = $er->createQueryBuilder('i')
                                    ->select(array('i'))
                                    ->where('i.game_id = :game_id')
                                    ->setParameter('game_id', $game_id)
                                    ->orderBy('i.name', 'ASC');

                            return $query;
                        },
                            )
                    );
                };

        //** Checks for Games That Are Submitted and Adds Servers and Categories Based on Game Selection **//
        $builder->get('game')->addEventListener(
                FormEvents::POST_SUBMIT, function(FormEvent $event) use ($formModifier) {
                    // Get Form Data to Pass Back to Modifier
                    $game = $event->getForm()->getData();
                    // Get Game Id to pass back to Form Modifier
                    $game_id = $event->getForm()->getData()->getId();
                    $formModifier($event->getForm()->getParent(), $game, $game_id);
                }
        );
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\MainBundle\Entity\Products'
        ));
    }

    /**
     * @return string
     */
    public function getName() {
        return 'acme_mainbundle_products';
    }

}

【问题讨论】:

    标签: jquery forms symfony doctrine-orm


    【解决方案1】:

    我通过这个 SO 条目 How to handle Ajax forms with collections in Symfony2.3 找到了 ajax 部分的答案

    这是我的实现

    javascript

    $(document).ready(function () {
        $('#acme_mainbundle_products_game').change(function(){
           if($(this).val()){
               $.ajax({
            type: "POST",
            url: "{{ url('productsCreateSubmit') }}",
            data: $(this).serialize(),
            success: function(data) {
                $('#dynamic_fields').html(data);
            }
        });
    
        return false; 
            }
        });
    });
    

    /new.html.twig 中的树枝

    {% 扩展 '::base.html.twig' %}

    {% 块体 -%}

        <h1>Products creation</h1>
        {{ form_start(form) }}
        <hr />
            {{ form_label(form.name) }}
            {{ form_errors(form.name) }}
            {{ form_widget(form.name) }}
        <hr />
            {{ form_label(form.price) }}
            {{ form_errors(form.price) }}
            {{ form_widget(form.price) }}
        <hr />
            {{ form_label(form.description) }}
            {{ form_errors(form.description) }}
            {{ form_widget(form.description) }}
        <hr />
            {{ form_label(form.game) }}
            {{ form_errors(form.game) }}
            {{ form_widget(form.game) }}
        <hr />
        <div id="dynamic_fields">Stuff Will Go Here</div>
    {{ form_end(form) }}
    

    serverslist.twig.html

    <hr />
     {{ form_label(form.server) }}
     {{ form_errors(form.server) }}
     {{ form_widget(form.server) }}
    <hr />
    <hr />
     {{ form_label(form.category) }}
     {{ form_errors(form.category) }}
     {{ form_widget(form.category) }}
    <hr />
    

    最后是控制器条目

    /**
     * @Route("/products/create/submit", name="productsCreateSubmit")
     */
    public function productsCreateSubmitAction(Request $request) {
        $products = new Products();
    
        $form = $this->createForm(new ProductsType(), $products);
        $form->handleRequest($request);
    
        return $this->render('AcmeMainBundle:Products:serverslist.html.twig', array(
                    'form' => $form->createView(),
        ));
    }
    

    我仍然需要完成验证,但这就是我执行 ajax 以仅呈现所需字段的方式。这似乎是正确的并且有效,但如果有人对如何做得更好有任何反馈,我很乐意听到反馈。

    【讨论】:

      【解决方案2】:

      我认为让 $game 对象这样使用它时有问题:

       //** Checks for Games That Are Submitted and Adds Servers and Categories Based on Game Selection **//
          $builder->get('game')->addEventListener(
                  FormEvents::POST_SUBMIT, function(FormEvent $event) use ($formModifier) {
                      // Get Form Data to Pass Back to Modifier
                      $game = $event->getForm()->getData()->getGame();
                      // Get Game Id to pass back to Form Modifier
                      $game_id = $game->getId();
                      $formModifier($event->getForm()->getParent(), $game, $game_id);
                  }
          );
      

      并且你不使用 $game 对象,你只在 $formModifier 中使用了 $game_id。所以你可以像这样改变你的功能:

       $formModifier = function(FormInterface $form, $game_id) {
          //Adding other widgets here
       }
      

      【讨论】:

      • 谢谢你我做了那个改变,你是对的,但这不是真正的问题。问题是字段最初不显示时的验证,以及如何根据游戏 ID 仅在提交时呈现新字段。
      猜你喜欢
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      • 2021-11-10
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多