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

#javascript #php #html #forms #symfony

#javascript #php #HTML #формы #symfony

Вопрос:

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

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

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

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

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

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

Спасибо.

Ответ №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 %}
 

Добавить 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() amp;amp; $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);
    }
 

Надеюсь, это может помочь кому-то еще. Действительно разочарован тем, насколько ограничены формы Symfony.