简体   繁体   English

Symfony Forms - 根据选择动态添加/删除字段

[英]Symfony Forms - dynamically add/remove fields depending on choices

I'm trying to create a form that maps to an entity of the type "Participant".我正在尝试创建一个映射到“参与者”类型的实体的表单。 A participant is in a one-to-one relationship with a 'person'.参与者与“人”是一对一的关系。 Adding a participant, I want to first give the option to choose a person already in the database and if the right one doesn't exist, create that person with the participant form.添加参与者,我想首先提供选择数据库中已有人的选项,如果不存在正确的人,则使用参与者表单创建该人。

This works if I do it with two pages/forms.如果我用两页/表格来做这件事。 The first one trying to choose an existing person, otherwise open a new page with the different form.第一个尝试选择现有人员,否则打开具有不同表单的新页面。 First page:第一页:

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

Second page:第二页:

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

Well, that works, but it's terribly slow and unecessary.嗯,这有效,但它非常缓慢且不必要。 What I'd rather want is having BOTH of those shown, where the PersonType form fields (first name, last name, title, company, address, etc.) are automatically populated with the persons data, if one is selected.我更想要的是同时显示这两个字段,其中 PersonType 表单字段(名字、姓氏、职位、公司、地址等)会自动填充人员数据(如果选择了一个)。 Otherwise, if no Person is selected and the form is submitted with data entered, a new Person should be created and persisted in the database.否则,如果没有选择 Person 并且提交了包含输入数据的表单,则应该创建一个新的 Person 并将其保存在数据库中。

It's sadly not possible to render the 'person' twice, once as a dropdown and once as a PersonType form.遗憾的是不可能将“人”呈现两次,一次作为下拉列表,一次作为 PersonType 表单。 So how would I go about achieving what I want, without surreal amounts of JavaScript?那么,如果没有超现实的 JavaScript 数量,我将如何实现我想要的?

My current solution would be to manually create all the required fields with JavaScript and populate them with the person data I'd get with another Ajax request on a onchange event on the person dropdown, then in the PRE_SUBMIT event of the form, remove the 'person' field and add it again as a PersonType field, check if the entered data corresponds to an existing person or a new one and then act accordingly.我目前的解决方案是使用 JavaScript 手动创建所有必填字段,并使用我在人员下拉菜单上的 onchange 事件上的另一个 Ajax 请求获得的人员数据填充它们,然后在表单的 PRE_SUBMIT 事件中,删除 ' person' 字段并将其再次添加为 PersonType 字段,检查输入的数据是否对应于现有人员或新人员,然后采取相应措施。 There has to be a better solution, right?必须有更好的解决方案,对吗?

Form events have sadly otherwise proven majorly pointless, as it's not possible to attach an event listener to a 'change' event on one of the fields.可悲的是,表单事件已被证明是毫无意义的,因为不可能将事件侦听器附加到字段之一的“更改”事件。

Thanks.谢谢。

Ended up solving it with an unmapped person choice field and javascript to automatically update the data (using ajax).最终使用未映射的人员选择字段和 javascript 来解决它以自动更新数据(使用 ajax)。

participant/add.twig:参与者/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 %}

ParticipantController add: ParticipantController 添加:

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

Hope this can help someone else.希望这可以帮助别人。 Really disappointed with how limited Symfonys Forms are.对 Symfonys Forms 的限制真的很失望。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM