【问题标题】:Symfony Forms - dynamically add/remove fields depending on choicesSymfony Forms - 根据选择动态添加/删除字段
【发布时间】:2019-04-17 17:07:51
【问题描述】:

我正在尝试创建一个映射到“参与者”类型的实体的表单。参与者与“人”处于一对一的关系。添加参与者,我想首先提供选择数据库中已有人的选项,如果不存在合适的人,则使用参与者表单创建该人。

如果我用两个页面/表单来做这件事,这很有效。第一个尝试选择现有人员,否则打开具有不同表单的新页面。 第一页:

$form->add('person', AjaxEntityType, [ // EntityType but with select2 ajax
    'class' => Person::class,
    'remote_route' => 'person_ajax_list'
]);

第二页:

$participant->setPerson(new Person());
$form->add('person', PersonType::class);
// adds PersonType fields to the Participant form

嗯,这行得通,但它非常缓慢且不必要。我想要的是显示其中的两个,其中 PersonType 表单字段(名字、姓氏、头衔、公司、地址等)自动填充人员数据(如果选择了一个)。否则,如果没有选择任何 Person 并且在提交表单时输入了数据,则应该创建一个新的 Person 并将其持久化到数据库中。

遗憾的是,无法将“人”渲染两次,一次作为下拉菜单,一次作为 PersonType 表单。那么在没有大量 JavaScript 的情况下,我将如何实现我想要的呢?

我当前的解决方案是使用 JavaScript 手动创建所有必填字段,并使用我在人员下拉列表的 onchange 事件上通过另一个 Ajax 请求获得的人员数据填充它们,然后在表单的 PRE_SUBMIT 事件中,删除“人员”字段并再次将其添加为 PersonType 字段,检查输入的数据是对应于现有人员还是新人员,然后采取相应措施。应该有更好的解决方案吧?

遗憾的是,表单事件在其他方面被证明毫无意义,因为不可能将事件侦听器附加到其中一个字段上的“更改”事件。

谢谢。

【问题讨论】:

    标签: javascript php html forms symfony


    【解决方案1】:

    最终使用未映射的人员选择字段和 javascript 来自动更新数据(使用 ajax)来解决它。

    参与者/add.twig:

    {% block javascripts %}
    
        <script type="text/javascript">
    
            $(document).ready(function () {
                function onTrainerChange() {
                    let trainerId = $('#participant_person_choose').val();
                    $.get(Routing.generate('person_data_ajax', { id: trainerId }), function (data) {
                        $('#participant_person_gender').val(data.gender);
                        $('#participant_person_title').val(data.title);
                        $('#participant_person_firstName').val(data.firstName);
                        $('#participant_person_lastName').val(data.lastName);
                        $('#participant_person_email').val(data.email);
                        $('#participant_person_telephone').val(data.telephone);
                        if (data.company) {
                            let company = $('#participant_person_company');
                            company.empty();
                            company.append(new Option(data.company.text, data.company.id));
                            company.val(data.company.id);
                            company.trigger('change');
                            // manipulate dom directly because of .select('data') bug with select2 >=4.0
                        }
                    });
                };
    
                let trainer = $('#participant_person_choose');
                trainer.change(onTrainerChange);
            });
    
        </script>
    
    {% endblock %}
    

    参与者控制器添加:

        $participant = new Participant($seminar);
        $person = $participant->getPerson() ?? new Person();
        $participant->setPerson($person);
        $form = $this->createParticipantForm($participant)
            ->add('person_choose', AjaxEntityType::class, [
                'mapped' => false,
                'class' => Person::class,
                'remote_route' => 'person_select_ajax',
                'placeholder' => 'form.personCreate',
                'label' => 'form.person'
            ])
            ->add('person', PersonType::class);
    
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
    
            if ($form->get('reservation')->getData()) {
                $participant->setInterested();
            }
    
            $personEntered = $form->get('person')->getData();
            $personChosen = $form->get('person_choose')->getData();
            if ($personChosen) {
                $person = $personChosen;
                $person->setGender($personEntered->getGender());
                $person->setTitle($personEntered->getTitle());
                $person->setFirstName($personEntered->getFirstName());
                $person->setFirstName($personEntered->getLastName());
                $person->setCompany($personEntered->getCompany());
                $person->setEmail($personEntered->getEmail());
                $person->setTelephone($personEntered->getTelephone());
                $participant->setPerson($person);
            }
    
            $this->getDoctrine()->getManager()->persist($person);
    
            $this->getDoctrine()->getManager()->persist($participant);
        }
    

    PersonController Ajax:

        /**
         * @Route("/{id}/data", name="person_data_ajax", methods={"GET"}, options={"expose": true})
         */
        public function dataAjax(Person $person, PhoneNumberHelper $phonenumberHelper)
        {
            $arr = [
                'id' => $person->id,
                'gender' => $person->getGender(),
                'title' => $person->getTitle(),
                'firstName' => $person->getFirstName(),
                'lastName' => $person->getLastName(),
                'email' => $person->getEMail(),
                'telephone' => $person->getTelephone() ? $phonenumberHelper->format($person->getTelephone(), PhoneNumberFormat::NATIONAL) : null,
                'company' => $person->getCompany() ? [
                    'id' => $person->getCompany()->id,
                    'text' => $person->getCompany()->__toString()
                ] : null
            ];
    
            return new JsonResponse($arr);
        }
    

    希望这可以帮助别人。对 Symfonys 表单的有限性感到非常失望。

    【讨论】:

      猜你喜欢
      • 2013-09-09
      • 1970-01-01
      • 2018-05-02
      • 2020-01-05
      • 2017-04-27
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多