0

I would like to have 3 choice fields where the options available depend on the selected value of the previous field.

Following the example from the docs, I manage to make this work for two choice fields: https://symfony.com/doc/current/form/dynamic_form_modification.html#dynamic-generation-for-submitted-forms

But I can't wrap my head around adding a third choice field. For example: Company -> Department -> Location

The company field has a FormEvents::POST_SUBMIT event listener via $builder->get('company')->addEventListener() because you can't add children to a submitted form, the event listener is added to a subform that can still add children to the parent form. Without this the data is empty on submit.

Which is a problem because the same event listener can't be added to the department field because when adding via $builder->get('department')->addEventListener() the field doesn't exists because it is added in the event listener.

// src/Form/Type/CompanyType.php
namespace App\Form\Type;

use App\Entity\Department;
use App\Entity\Company;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormInterface;
// ...

class CompanyMeetupType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('company', EntityType::class, [
                'class' => Company::class,
                'placeholder' => '',
            ])
        ;

        $formModifier = function (FormInterface $form, Company $company = null) {
            $departments = null === $company ? [] : $company->getAvailableDepartments();

            $form->add('department', EntityType::class, [
                'class' => Department::class,
                'placeholder' => '',
                'choices' => $$departments,
            ]);
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                $data = $event->getData();

                $formModifier($event->getForm(), $data->getCompany());
            }
        );

        $builder->get('company')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                // It's important here to fetch $event->getForm()->getData(), as
                // $event->getData() will get you the client data (that is, the ID)
                $company = $event->getForm()->getData();

                // since we've added the listener to the child, we'll have to pass on
                // the parent to the callback functions!
                $formModifier($event->getForm()->getParent(), $company);
            }
        );
    }

    // ...
}

1 Answers1

1

https://stackoverflow.com/a/29519301/15114115 solved this.

This is the jQuery that I wrote with it:

$(document).ready(function () {
    var $form = $('form[name=company_meetup]');

    $form.on('change', '#company_meetup_company', function() {
        var $field = $(this);
        var $form = $field.closest('form');
        var data = {};
        data[$field.attr('name')] = $field.val();
        $.ajax({
            url : $form.attr('action'),
            type: $form.attr('method'),
            data : data,
            success: function(html) {
                $('#company_meetup_department').replaceWith(
                    $(html).find('#company_meetup_department')
                );
                $('#company_meetup_location').replaceWith(
                    $(html).find('#company_meetup_location')
                );
            }
        });
    });

    $form.on('change', '#company_meetup_department', function() {
        var $field = $(this);
        var $form = $field.closest('form');
        var data = {};
        data[$field.attr('name')] = $field.val();
        $.ajax({
            url : $form.attr('action'),
            type: $form.attr('method'),
            data : data,
            success: function(html) {
                $('#company_meetup_location').replaceWith(
                    $(html).find('#company_meetup_location')
                );
            }
        });
    });
})