Search code examples
symfony4symfony-formssymfony-validator

Symfony 4.3.5 - formbuilder and errors validation for update parent relation


I create VehicleType:

class VehicleType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->add('name')
                ->add('user', EntityType::class, [
                    'class' => User::class,
                    'choice_label' => 'email',
                ])
                ->add('vehicleBrand', EntityType::class, [
                    'placeholder' => 'Choose an vehicle brand',
                    'class' => VehicleBrand::class,
                    'choice_label' => 'name',
                    "attr" => array(
                        "class" => "form-control"
                    )
                ])
                ->add('vehicleModel', EntityType::class, array(
                    'placeholder' => 'Choose an vehicle model',
                    'class' => VehicleModel::class,
                    'choice_label' => 'name',
                    'multiple' => false,
                    'expanded' => false,
                ))
        ;

        $formModifier = function (FormInterface $form, VehicleBrand $vehicleBrand = null) {
            $models = null === $vehicleBrand ? array() : $vehicleBrand->getVehicleModels();
            $form->add('vehicleModel', EntityType::class, array(
                'placeholder' => 'Choose an option',
                'class' => VehicleModel::class,
                'choice_label' => 'name',
                'choices' => $models,
                'multiple' => false,
                'expanded' => false,
            ));
        };

        $builder->addEventListener(
                FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) {
            $data = $event->getData();
            $brand = null !== $data->getVehicleBrand() ? $data->getVehicleBrand() : null !== $data->getVehicleModel() ? $data->getVehicleModel()->getBrand() : null;
            $formModifier($event->getForm(), $brand);
            if (!$data->getVehicleBrand() && $data->getVehicleModel()) {
                $event->getForm()->add('vehicleBrand', EntityType::class, [
                    'placeholder' => 'Choose an option',
                    'class' => VehicleBrand::class,
                    'choice_label' => 'name',
                    "attr" => array(
                        "class" => "form-control"
                    ),
                    'data' => $data->getVehicleModel()->getBrand()
                ]);
            }
        }
        );

        $builder->get('vehicleBrand')->addEventListener(
                FormEvents::POST_SUBMIT, function (FormEvent $event) use ($formModifier) {
            $brand = $event->getForm()->getData();
            $formModifier($event->getForm()->getParent(), $brand);
        }
        );
    }

}

javascript to update vehicle Model after select vehicle brand:

$('#vehicle_vehicleBrand').on('change', function () {
    var brandId = this.value;
    if (brandId < 1) {
        $("#vehicle_vehicleModel").prop('disabled', 'disabled');
        return;
    }
    $.getJSON("/api/v2/vehiclemodels/" + brandId + "/brands.json", function (j) {
        var options = '<option value="0">' + $("#vehicle_vehicleModel option:first").text() + '</option>';
        for (var i = 0; i < j.length; i++) {
            options += '<option value="' + j[i].id + '">' + j[i].name + '</option>';
        }
        $("#vehicle_vehicleModel").removeAttr("disabled");
        $('#vehicle_vehicleModel').html(options);
    });
});

this code is very complicated but it almost works

I can create new vehicle, i can edit vehicle with the same brand, but when i change brand and select new vehicle model i see error "This value is not valid."

What's going on? Meybe i should add new type of FormEvents?

Thanks for help


Solution

  • I found a solution:

    class VehicleType extends AbstractType {
    
        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder
                    ->add('name')
                    ->add('user', EntityType::class, [
                        'class' => User::class,
                        'choice_label' => 'email',
                    ])
                    ->add('vehicleBrand', EntityType::class, [
                        'placeholder' => 'Choose an vehicle brand',
                        'class' => VehicleBrand::class,
                        'choice_label' => 'name',
                        "attr" => array(
                            "class" => "form-control"
                        )
                    ])
                    ->add('vehicleModel', EntityType::class, array(
                        'placeholder' => 'Choose an vehicle model',
                        'class' => VehicleModel::class,
                        'choice_label' => 'name',
                        'multiple' => false,
                        'expanded' => false,
                    ))
            ;
    
            $formModifier = function (FormInterface $form, VehicleBrand $vehicleBrand = null) {
                $models = null === $vehicleBrand ? array() : $vehicleBrand->getVehicleModels();
                $form->add('vehicleModel', EntityType::class, array(
                    'placeholder' => 'Choose an option',
                    'class' => VehicleModel::class,
                    'choice_label' => 'name',
                    'choices' => $models,
                    'multiple' => false,
                    'expanded' => false,
                ));
            };
    
            $builder->addEventListener(
                    FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) {
                $data = $event->getData();
                $vehicleModelBrand = null !== $data->getVehicleModel() ? $data->getVehicleModel()->getBrand() : null;
                $vehicleBrand = null !== $data->getVehicleBrand() ? $data->getVehicleBrand() : null;
                $brand = null !== $vehicleModelBrand ? $vehicleModelBrand : $vehicleBrand;
                $formModifier($event->getForm(), $brand, $data->getVehicleModel());
                $data->setVehicleBrand($brand);
            }
            );
    
            $builder->get('vehicleBrand')->addEventListener(
                    FormEvents::POST_SUBMIT, function (FormEvent $event) use ($formModifier) {
                $brand = $event->getForm()->getData();
                $formModifier($event->getForm()->getParent(), $brand);
            }
            );
        }
    
    }
    

    Thanks for help :)