Skip to content

Commit a75ad9c

Browse files
committed
Shorten AJAX example
1 parent ee33dcd commit a75ad9c

File tree

2 files changed

+35
-105
lines changed

2 files changed

+35
-105
lines changed

cookbook/form/dynamic_form_modification.rst

+10-105
Original file line numberDiff line numberDiff line change
@@ -614,22 +614,13 @@ your application. Assume that you have a sport meetup creation controller::
614614
namespace Acme\DemoBundle\Controller;
615615

616616
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
617-
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
618-
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
619617
use Symfony\Component\HttpFoundation\Request;
620618
use Acme\DemoBundle\Entity\SportMeetup;
621619
use Acme\DemoBundle\Form\Type\SportMeetupType;
622620
// ...
623621

624-
/**
625-
* @Route("/meetup")
626-
*/
627622
class MeetupController extends Controller
628623
{
629-
/**
630-
* @Route("/create", name="meetup_create")
631-
* @Template
632-
*/
633624
public function createAction(Request $request)
634625
{
635626
$meetup = new SportMeetup();
@@ -639,15 +630,17 @@ your application. Assume that you have a sport meetup creation controller::
639630
// ... save the meetup, redirect etc.
640631
}
641632

642-
return array('form' => $form->createView());
633+
return $this->render(
634+
'AcmeDemoBundle:Meetup:create.html.twig',
635+
array('form' => $form->createView())
636+
);
643637
}
644638

645639
// ...
646640
}
647641

648642
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:
651644

652645
.. configuration-block::
653646

@@ -660,31 +653,7 @@ it makes use of `jQuery`_ library and the `FOSJsRoutingBundle`_:
660653
{# ... #}
661654
{{ form_end(form) }}
662655

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
688657

689658
.. code-block:: html+php
690659

@@ -695,72 +664,11 @@ it makes use of `jQuery`_ library and the `FOSJsRoutingBundle`_:
695664
<!-- ... -->
696665
<?php echo $view['form']->end($form) ?>
697666

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
729668

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.
764672

765673
.. _cookbook-dynamic-form-modification-suppressing-form-validation:
766674

@@ -793,6 +701,3 @@ all of this, use a listener::
793701

794702
By doing this, you may accidentally disable something more than just form
795703
validation, since the ``POST_SUBMIT`` event may have other listeners.
796-
797-
.. _`jQuery`: http://jquery.com
798-
.. _`FOSJsRoutingBundle`: https://github.com/FriendsOfSymfony/FOSJsRoutingBundle
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script>
2+
var $sport = $('#meetup_sport');
3+
// When sport gets selected ...
4+
$sport.change(function(){
5+
// ... retrieve the corresponding form.
6+
var $form = $(this).closest('form');
7+
// Simulate form data, but only include the selected sport value.
8+
var data = {};
9+
data[$sport.attr('name')] = $sport.val();
10+
// Submit data via AJAX to the form's action path.
11+
$.ajax({
12+
url : $form.attr('action'),
13+
type: $form.attr('method'),
14+
data : data,
15+
success: function(html) {
16+
// Replace current position field ...
17+
$('#meetup_position').replaceWith(
18+
// ... with the returned one from the AJAX response.
19+
$(html).find('#meetup_position')
20+
);
21+
// Position field now displays the appropriate positions.
22+
}
23+
});
24+
});
25+
</script>

0 commit comments

Comments
 (0)