Pierre Olivier Tran
Pierre Olivier Tran

Reputation: 1879

Specific choices through entity form

I'm trying to generate a specific form.

I have two classes, City and Airport.

Every city got a few airport thanks to a OneToMany relationship.

When a user selects an airport, I would like to display only the ones that belong to a particular city. Is there a way to do so ?

So far, my form field looks like this :

            ->add('departure', 'entity', array(
'class' => 'AOFVHFlyBundle:Airport',
'property' => 'name',
'label' => 'Departure'
))

Upvotes: 0

Views: 124

Answers (1)

Veve
Veve

Reputation: 6748

What you describe is (almost) exactly one of the documentation examples, I've adapted it for your need but I encourage you to read it.

Add an event listener on the PRE_SET_DATA event to dynamically add the Airportfield, and a POST_SUBMIT listener to the field that this new field depends on. If you add a POST_SUBMIT listener to a form child (e.g. sport), and add new children to the parent form, the Form component will detect the new field automatically and map it to the submitted client data.

YourGlobalEntityType.php

<?php
// src/AOFVHFlyBundle/Form/Type/YourGlobalEntityType.php
namespace AOFVHFlyBundle\Form\Type;

// ...
use Symfony\Component\Form\FormInterface;
use AOFVHFlyBundle\Entity\City;
use AOFVHFlyBundle\Entity\Airport;

class YourGlobalEntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('city', 'entity', array(
                'class'    => 'AOFVHFlyBundle:Airport',
                'property' => 'name',
                'label'    => 'Departure'
            ))
        ;

        $formModifier = function (FormInterface $form, City $city = null) {
            $airports = null === $city ? array() : $city->getAvailableAirports();

            $form->add('departure', 'entity', array(
                'class'       => 'AOFVHFlyBundle:Airport',
                'property'    => 'name',
                'choices'     => $airports,
                'label'       => 'Departure',
            ));
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                // this would be your entity, i.e. YourGlobalEntity
                $data = $event->getData();

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

        $builder->get('city')->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)
                $city = $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(), $city);
            }
        );
    }

    // ...
}

Then in your Twig, add the javascript needed to make it dynamic:

{# src/AOFVHFlyBundle/Resources/views/YourGlobalEntity/create.html.twig #}
{{ form_start(form) }}
    {{ form_row(form.city, { 'attr': { 'class':'yourglobalentity_city' } } ) }}
    {{ form_row(form.departure, { 'attr': { 'class':'yourglobalentity_departure' } } ) }}
    {# ... #}
{{ form_end(form) }}

<script>
var $city = $('.yourglobalentity_city');
// When city gets selected ...
$city.change(function() {
  // ... retrieve the corresponding form.
  var $form = $(this).closest('form');
  // Simulate form data, but only include the selected city value.
  var data = {};
  data[$city.attr('name')] = $city.val();
  // Submit data via AJAX to the form's action path.
  $.ajax({
    url : $form.attr('action'),
    type: $form.attr('method'),
    data : data,
    success: function(html) {
      // Replace current position field ...
      $('.yourglobalentity_departure').replaceWith(
        // ... with the returned one from the AJAX response.
        $(html).find('.yourglobalentity_departure')
      );
      // Position field now displays the appropriate positions.
    }
  });
});
</script>

Upvotes: 1

Related Questions