Symfony Forms — динамически добавлять/удалять поля в зависимости от выбора

Я пытаюсь создать форму, которая сопоставляется с сущностью типа «Участник». Участник находится в отношениях один на один с «человеком». Добавляя участника, я хочу сначала дать возможность выбрать человека, который уже есть в базе данных, и, если нужного человека не существует, создать этого человека с помощью формы участника.

Это работает, если я делаю это с двумя страницами/формами. Первый пытается выбрать существующего человека, в противном случае открывается новая страница с другой формой. Первая страница:

$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 (имя, фамилия, должность, компания, адрес и т. д.) автоматически заполняются данными о лицах, если они выбраны. В противном случае, если ни одно лицо не выбрано и форма отправлена ​​с введенными данными, необходимо создать новое лицо и сохранить его в базе данных.

К сожалению, невозможно отобразить «человека» дважды, один раз как раскрывающийся список и один раз как форму PersonType. Итак, как мне достичь того, чего я хочу, без сюрреалистического количества JavaScript?

Моим текущим решением было бы вручную создать все необходимые поля с помощью JavaScript и заполнить их данными о человеке, которые я получил бы с помощью другого запроса Ajax в событии onchange в раскрывающемся списке людей, а затем в событии PRE_SUBMIT формы удалить ' человека» и добавьте его снова как поле PersonType, проверьте, соответствуют ли введенные данные существующему или новому человеку, и затем действуйте соответственно. Должно быть лучшее решение, не так ли?

К сожалению, в противном случае события формы оказались в значительной степени бессмысленными, поскольку невозможно прикрепить прослушиватель событий к событию «изменения» в одном из полей.

Спасибо.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
663
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В итоге решил это с помощью несопоставленного поля выбора человека и javascript для автоматического обновления данных (используя ajax).

участник/доп.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 Forms.

Другие вопросы по теме