@@ -614,22 +614,13 @@ your application. Assume that you have a sport meetup creation controller::
614
614
namespace Acme\DemoBundle\Controller;
615
615
616
616
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
617
- use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
618
- use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
619
617
use Symfony\Component\HttpFoundation\Request;
620
618
use Acme\DemoBundle\Entity\SportMeetup;
621
619
use Acme\DemoBundle\Form\Type\SportMeetupType;
622
620
// ...
623
621
624
- /**
625
- * @Route("/meetup")
626
- */
627
622
class MeetupController extends Controller
628
623
{
629
- /**
630
- * @Route("/create", name="meetup_create")
631
- * @Template
632
- */
633
624
public function createAction(Request $request)
634
625
{
635
626
$meetup = new SportMeetup();
@@ -639,15 +630,17 @@ your application. Assume that you have a sport meetup creation controller::
639
630
// ... save the meetup, redirect etc.
640
631
}
641
632
642
- return array('form' => $form->createView());
633
+ return $this->render(
634
+ 'AcmeDemoBundle:Meetup:create.html.twig',
635
+ array('form' => $form->createView())
636
+ );
643
637
}
644
638
645
639
// ...
646
640
}
647
641
648
642
The associated template uses some JavaScript to update the ``position `` form
649
- field according to the current selection in the ``sport `` field. To ease things
650
- it makes use of `jQuery `_ library and the `FOSJsRoutingBundle `_:
643
+ field according to the current selection in the ``sport `` field:
651
644
652
645
.. configuration-block ::
653
646
@@ -660,31 +653,7 @@ it makes use of `jQuery`_ library and the `FOSJsRoutingBundle`_:
660
653
{# ... #}
661
654
{{ form_end(form) }}
662
655
663
- {# ... Include jQuery and scripts from FOSJsRoutingBundle ... #}
664
- <script>
665
- $(function(){
666
- // When sport gets selected ...
667
- $('#meetup_sport').change(function(){
668
- var $position = $('#meetup_position');
669
- // Remove current position options except first "empty_value" option
670
- $position.find('option:not(:first)').remove();
671
- var sportId = $(this).val();
672
- if (sportId) {
673
- // Issue AJAX call fetching positions for selected sport as JSON
674
- $.getJSON(
675
- // FOSJsRoutingBundle generates route including selected sport ID
676
- Routing.generate('meetup_positions_by_sport', {id: sportId}),
677
- function(positions) {
678
- // Append fetched positions associated with selected sport
679
- $.each(positions, function(key, position){
680
- $position.append(new Option(position[1], position[0]));
681
- });
682
- }
683
- );
684
- }
685
- });
686
- });
687
- </script>
656
+ .. include :: /cookbook/form/dynamic_form_modification_ajax_js.rst.inc
688
657
689
658
.. code-block :: html+php
690
659
@@ -695,72 +664,11 @@ it makes use of `jQuery`_ library and the `FOSJsRoutingBundle`_:
695
664
<!-- ... -->
696
665
<?php echo $view['form']->end($form) ?>
697
666
698
- <!-- ... Include jQuery and scripts from FOSJsRoutingBundle ... -->
699
- <script>
700
- $(function(){
701
- // When sport gets selected ...
702
- $('#meetup_sport').change(function(){
703
- var $position = $('#meetup_position');
704
- // Remove current position options except first "empty_value" option
705
- $position.find('option:not(:first)').remove();
706
- var sportId = $(this).val();
707
- if (sportId) {
708
- // Issue AJAX call fetching positions for selected sport as JSON
709
- $.getJSON(
710
- // FOSJsRoutingBundle generates route including selected sport ID
711
- Routing.generate('meetup_positions_by_sport', {id: sportId}),
712
- function(positions) {
713
- // Append fetched positions associated with selected sport
714
- $.each(positions, function(key, position){
715
- $position.append(new Option(position[1], position[0]));
716
- });
717
- }
718
- );
719
- }
720
- });
721
- });
722
- </script>
723
-
724
- The last piece is implementing a controller for the
725
- ``meetup_positions_by_sport `` route returning the positions as JSON according
726
- to the currently selected sport. To ease things again the controller makes use
727
- of the :doc: `@ParamConverter </bundles/SensioFrameworkExtraBundle/annotations/converters >`
728
- listener to convert the submitted sport ID into a ``Sport `` object::
667
+ .. include :: /cookbook/form/dynamic_form_modification_ajax_js.rst.inc
729
668
730
- // src/Acme/DemoBundle/Controller/MeetupController.php
731
- namespace Acme\DemoBundle\Controller;
732
-
733
- // ...
734
- use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
735
- use Symfony\Component\HttpFoundation\JsonResponse;
736
- use Acme\DemoBundle\Entity\Sport;
737
-
738
- /**
739
- * @Route("/meetup")
740
- */
741
- class MeetupController extends Controller
742
- {
743
- // ...
744
-
745
- /**
746
- * @Route("/{id}/positions.json", name="meetup_positions_by_sport", options={"expose"=true})
747
- */
748
- public function positionsBySportAction(Sport $sport)
749
- {
750
- $result = array();
751
- foreach ($sport->getAvailablePositions() as $position) {
752
- $result[] = array($position->getId(), $position->getName());
753
- }
754
-
755
- return new JsonResponse($result);
756
- }
757
- }
758
-
759
- .. note ::
760
-
761
- The returned JSON should not be created from an associative array
762
- (``$result[$position->getId()] = $position->getName()) ``) as the iterating
763
- order in JavaScript is undefined and may vary in different browsers.
669
+ The major benefit of submitting the whole form to just extract the updated
670
+ ``position `` field is that no additional server-side code is needed; all the
671
+ code from above to generate the submitted form can be reused.
764
672
765
673
.. _cookbook-dynamic-form-modification-suppressing-form-validation :
766
674
@@ -793,6 +701,3 @@ all of this, use a listener::
793
701
794
702
By doing this, you may accidentally disable something more than just form
795
703
validation, since the ``POST_SUBMIT `` event may have other listeners.
796
-
797
- .. _`jQuery` : http://jquery.com
798
- .. _`FOSJsRoutingBundle` : https://github.com/FriendsOfSymfony/FOSJsRoutingBundle
0 commit comments