@@ -474,8 +474,10 @@ The meetup is passed as an entity field to the form. So we can access each
474
474
sport like this::
475
475
476
476
// src/Acme/DemoBundle/Form/Type/SportMeetupType.php
477
+
477
478
namespace Acme\DemoBundle\Form\Type;
478
479
480
+ use Symfony\Component\Form\AbstractType;
479
481
use Symfony\Component\Form\FormBuilderInterface;
480
482
use Symfony\Component\Form\FormEvent;
481
483
use Symfony\Component\Form\FormEvents;
@@ -487,9 +489,9 @@ sport like this::
487
489
{
488
490
$builder
489
491
->add('sport', 'entity', array(
490
- 'class' => 'AcmeDemoBundle:Sport',
492
+ 'class' => 'AcmeDemoBundle:Sport',
491
493
'empty_value' => '',
492
- ));
494
+ ))
493
495
;
494
496
495
497
$builder->addEventListener(
@@ -501,16 +503,17 @@ sport like this::
501
503
$data = $event->getData();
502
504
503
505
$sport = $data->getSport();
504
- $positions = ( null === $sport) ? array() : $sport->getAvailablePositions();
506
+ $positions = null === $sport ? array() : $sport->getAvailablePositions();
505
507
506
508
$form->add('position', 'entity', array(
507
- 'class' => 'AcmeDemoBundle:Position',
509
+ 'class' => 'AcmeDemoBundle:Position',
508
510
'empty_value' => '',
509
- 'choices' => $positions,
511
+ 'choices' => $positions,
510
512
));
511
513
}
512
514
);
513
515
}
516
+
514
517
// ...
515
518
}
516
519
@@ -545,30 +548,31 @@ new field automatically and map it to the submitted client data.
545
548
The type would now look like::
546
549
547
550
// src/Acme/DemoBundle/Form/Type/SportMeetupType.php
551
+
548
552
namespace Acme\DemoBundle\Form\Type;
549
553
550
554
// ...
551
- use Acme\DemoBundle\Entity\Sport;
552
555
use Symfony\Component\Form\FormInterface;
556
+ use Acme\DemoBundle\Entity\Sport;
553
557
554
558
class SportMeetupType extends AbstractType
555
559
{
556
560
public function buildForm(FormBuilderInterface $builder, array $options)
557
561
{
558
562
$builder
559
563
->add('sport', 'entity', array(
560
- 'class' => 'AcmeDemoBundle:Sport',
564
+ 'class' => 'AcmeDemoBundle:Sport',
561
565
'empty_value' => '',
562
566
));
563
567
;
564
568
565
569
$formModifier = function(FormInterface $form, Sport $sport = null) {
566
- $positions = ( null === $sport) ? array() : $sport->getAvailablePositions();
570
+ $positions = null === $sport ? array() : $sport->getAvailablePositions();
567
571
568
572
$form->add('position', 'entity', array(
569
- 'class' => 'AcmeDemoBundle:Position',
573
+ 'class' => 'AcmeDemoBundle:Position',
570
574
'empty_value' => '',
571
- 'choices' => $positions,
575
+ 'choices' => $positions,
572
576
));
573
577
};
574
578
@@ -595,6 +599,7 @@ The type would now look like::
595
599
}
596
600
);
597
601
}
602
+
598
603
// ...
599
604
}
600
605
@@ -608,6 +613,15 @@ the sport is selected. This should be handled by making an AJAX call back to
608
613
your application. Assume that you have a sport meetup creation controller::
609
614
610
615
// src/Acme/DemoBundle/Controller/MeetupController.php
616
+
617
+ namespace Acme\DemoBundle\Controller;
618
+
619
+ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
620
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
621
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
622
+ use Symfony\Component\HttpFoundation\Request;
623
+ use Acme\DemoBundle\Entity\SportMeetup;
624
+ use Acme\DemoBundle\Form\Type\SportMeetupType;
611
625
// ...
612
626
613
627
/**
@@ -620,7 +634,6 @@ your application. Assume that you have a sport meetup creation controller::
620
634
* @Template
621
635
*/
622
636
public function createAction(Request $request)
623
-
624
637
{
625
638
$meetup = new SportMeetup();
626
639
$form = $this->createForm(new SportMeetupType(), $meetup);
@@ -631,47 +644,87 @@ your application. Assume that you have a sport meetup creation controller::
631
644
632
645
return array('form' => $form->createView());
633
646
}
647
+
634
648
// ...
635
649
}
636
650
637
651
The associated template uses some JavaScript to update the ``position `` form
638
652
field according to the current selection in the ``sport `` field. To ease things
639
653
it makes use of `jQuery `_ library and the `FOSJsRoutingBundle `_:
640
654
641
- .. code-block :: html+jinja
642
-
643
- {# src/Acme/DemoBundle/Resources/views/Meetup/create.html.twig #}
644
- {{ form_start(form) }}
645
- {{ form_row(form.sport) }} {# <select id="meetup_sport" ... #}
646
- {{ form_row(form.position) }} {# <select id="meetup_position" ... #}
647
- {# ... #}
648
- {{ form_end(form) }}
649
-
650
- {# ... Include jQuery and scripts from FOSJsRoutingBundle ... #}
651
- <script>
652
- $(function(){
653
- // When sport gets selected ...
654
- $('#meetup_sport').change(function(){
655
- var $position = $('#meetup_position');
656
- // Remove current position options except first "empty_value" option
657
- $position.find('option:not(:first)').remove();
658
- var sportId = $(this).val();
659
- if (sportId) {
660
- // Issue AJAX call fetching positions for selected sport as JSON
661
- $.getJSON(
662
- // FOSJsRoutingBundle generates route including selected sport ID
663
- Routing.generate('meetup_positions_by_sport', {id: sportId}),
664
- function(positions) {
665
- // Append fetched positions associated with selected sport
666
- $.each(positions, function(key, position){
667
- $position.append(new Option(position[1], position[0]));
668
- });
669
- }
670
- );
671
- }
655
+ .. configuration-block ::
656
+
657
+ .. code-block :: html+jinja
658
+
659
+ {# src/Acme/DemoBundle/Resources/views/Meetup/create.html.twig #}
660
+
661
+ {{ form_start(form) }}
662
+ {{ form_row(form.sport) }} {# <select id="meetup_sport" ... #}
663
+ {{ form_row(form.position) }} {# <select id="meetup_position" ... #}
664
+ {# ... #}
665
+ {{ form_end(form) }}
666
+
667
+ {# ... Include jQuery and scripts from FOSJsRoutingBundle ... #}
668
+ <script>
669
+ $(function(){
670
+ // When sport gets selected ...
671
+ $('#meetup_sport').change(function(){
672
+ var $position = $('#meetup_position');
673
+ // Remove current position options except first "empty_value" option
674
+ $position.find('option:not(:first)').remove();
675
+ var sportId = $(this).val();
676
+ if (sportId) {
677
+ // Issue AJAX call fetching positions for selected sport as JSON
678
+ $.getJSON(
679
+ // FOSJsRoutingBundle generates route including selected sport ID
680
+ Routing.generate('meetup_positions_by_sport', {id: sportId}),
681
+ function(positions) {
682
+ // Append fetched positions associated with selected sport
683
+ $.each(positions, function(key, position){
684
+ $position.append(new Option(position[1], position[0]));
685
+ });
686
+ }
687
+ );
688
+ }
689
+ });
672
690
});
673
- });
674
- </script>
691
+ </script>
692
+
693
+ .. code-block :: html+php
694
+
695
+ <!-- src/Acme/DemoBundle/Resources/views/Meetup/create.html.php -->
696
+
697
+ <?php echo $view['form']->start($form) ?>
698
+ <?php echo $view['form']->row($form['sport']) ?> <!-- <select id="meetup_sport" ... -->
699
+ <?php echo $view['form']->row($form['position']) ?> <!-- <select id="meetup_position" ... -->
700
+ <!-- ... -->
701
+ <?php echo $view['form']->end($form) ?>
702
+
703
+ <!-- ... Include jQuery and scripts from FOSJsRoutingBundle ... -->
704
+ <script>
705
+ $(function(){
706
+ // When sport gets selected ...
707
+ $('#meetup_sport').change(function(){
708
+ var $position = $('#meetup_position');
709
+ // Remove current position options except first "empty_value" option
710
+ $position.find('option:not(:first)').remove();
711
+ var sportId = $(this).val();
712
+ if (sportId) {
713
+ // Issue AJAX call fetching positions for selected sport as JSON
714
+ $.getJSON(
715
+ // FOSJsRoutingBundle generates route including selected sport ID
716
+ Routing.generate('meetup_positions_by_sport', {id: sportId}),
717
+ function(positions) {
718
+ // Append fetched positions associated with selected sport
719
+ $.each(positions, function(key, position){
720
+ $position.append(new Option(position[1], position[0]));
721
+ });
722
+ }
723
+ );
724
+ }
725
+ });
726
+ });
727
+ </script>
675
728
676
729
The last piece is implementing a controller for the
677
730
``meetup_positions_by_sport `` route returning the positions as JSON according
@@ -680,15 +733,21 @@ of the :doc:`@ParamConverter </bundles/SensioFrameworkExtraBundle/annotations/co
680
733
listener to convert the submitted sport ID into a ``Sport `` object::
681
734
682
735
// src/Acme/DemoBundle/Controller/MeetupController.php
736
+
737
+ namespace Acme\DemoBundle\Controller;
738
+
683
739
// ...
684
740
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
741
+ use Symfony\Component\HttpFoundation\JsonResponse;
742
+ use Acme\DemoBundle\Entity\Sport;
685
743
686
744
/**
687
745
* @Route("/meetup")
688
746
*/
689
747
class MeetupController extends Controller
690
748
{
691
749
// ...
750
+
692
751
/**
693
752
* @Route("/{id}/positions.json", name="meetup_positions_by_sport", options={"expose"=true})
694
753
*/
0 commit comments