diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index 14ad9f02756..b963bab1e5d 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -476,6 +476,7 @@ sport like this:: // src/Acme/DemoBundle/Form/Type/SportMeetupType.php namespace Acme\DemoBundle\Form\Type; + use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; @@ -486,7 +487,10 @@ sport like this:: public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('sport', 'entity', array(...)) + ->add('sport', 'entity', array( + 'class' => 'AcmeDemoBundle:Sport', + 'empty_value' => '', + )) ; $builder->addEventListener( @@ -497,12 +501,19 @@ sport like this:: // this would be your entity, i.e. SportMeetup $data = $event->getData(); - $positions = $data->getSport()->getAvailablePositions(); + $sport = $data->getSport(); + $positions = null === $sport ? array() : $sport->getAvailablePositions(); - $form->add('position', 'entity', array('choices' => $positions)); + $form->add('position', 'entity', array( + 'class' => 'AcmeDemoBundle:Position', + 'empty_value' => '', + 'choices' => $positions, + )); } ); } + + // ... } When you're building this form to display to the user for the first time, @@ -539,21 +550,28 @@ The type would now look like:: namespace Acme\DemoBundle\Form\Type; // ... - use Acme\DemoBundle\Entity\Sport; use Symfony\Component\Form\FormInterface; + use Acme\DemoBundle\Entity\Sport; class SportMeetupType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('sport', 'entity', array(...)) + ->add('sport', 'entity', array( + 'class' => 'AcmeDemoBundle:Sport', + 'empty_value' => '', + )); ; - $formModifier = function(FormInterface $form, Sport $sport) { - $positions = $sport->getAvailablePositions(); + $formModifier = function(FormInterface $form, Sport $sport = null) { + $positions = null === $sport ? array() : $sport->getAvailablePositions(); - $form->add('position', 'entity', array('choices' => $positions)); + $form->add('position', 'entity', array( + 'class' => 'AcmeDemoBundle:Position', + 'empty_value' => '', + 'choices' => $positions, + )); }; $builder->addEventListener( @@ -579,17 +597,78 @@ The type would now look like:: } ); } + + // ... + } + +You can see that you need to listen on these two events and have different +callbacks only because in two different scenarios, the data that you can use is +available in different events. Other than that, the listeners always perform +exactly the same things on a given form. + +One piece that is still missing is the client-side updating of your form after +the sport is selected. This should be handled by making an AJAX call back to +your application. Assume that you have a sport meetup creation controller:: + + // src/Acme/DemoBundle/Controller/MeetupController.php + namespace Acme\DemoBundle\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Request; + use Acme\DemoBundle\Entity\SportMeetup; + use Acme\DemoBundle\Form\Type\SportMeetupType; + // ... + + class MeetupController extends Controller + { + public function createAction(Request $request) + { + $meetup = new SportMeetup(); + $form = $this->createForm(new SportMeetupType(), $meetup); + $form->handleRequest($request); + if ($form->isValid()) { + // ... save the meetup, redirect etc. + } + + return $this->render( + 'AcmeDemoBundle:Meetup:create.html.twig', + array('form' => $form->createView()) + ); + } + + // ... } -You can see that you need to listen on these two events and have different callbacks -only because in two different scenarios, the data that you can use is available in different events. -Other than that, the listeners always perform exactly the same things on a given form. +The associated template uses some JavaScript to update the ``position`` form +field according to the current selection in the ``sport`` field: + +.. configuration-block:: + + .. code-block:: html+jinja + + {# src/Acme/DemoBundle/Resources/views/Meetup/create.html.twig #} + {{ form_start(form) }} + {{ form_row(form.sport) }} {#