Как заполнить выпадающий список динамически в symfony? (выберите города региона)

Я объясняю свою проблему:

Я должен создать форму, в которой раскрывающиеся списки заполняются в соответствии с нашими выборами в предыдущих.

У меня есть два объекта:

Регион может иметь несколько связей (ManyToOne).

Я следил за документацией здесь. Как динамически изменять формы с помощью событий формы (динамическое поколение для отправленных форм) .

Вот код для объектов:

Регион:

class Region { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="nom", type="string", length=255) */ private $nom; /** * @var int * * @ORM\Column(name="numero", type="smallint") */ private $numero; } 

Ville Entity:

 class Ville { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="nom", type="string", length=255) */ private $nom; /** * @var int * * @ORM\Column(name="numero", type="smallint") */ private $numero; /** * @var int * * @ORM\Column(name="codePostal", type="smallint") */ private $codePostal; /** * @var Region * * @ORM\ManyToOne(targetEntity="GE\CandidatBundle\Entity\Region") */ protected $region; } 

моя проблема:

Я извлекаю список регионов с параметром query_builder, но как получить список городов в соответствии с выбором региона .

AnnonceType:

  $builder ->add('region', EntityType::class, [ 'label' => 'Region *', 'label_attr' => [ "class" => "smaller lighter blue", "style" => "font-size: 21px;", ], 'class' => 'GECandidatBundle:Region', 'choice_label' => 'nom', 'multiple' => false, 'query_builder' => function(RegionRepository $repository) { return $repository->getListeRegion(); } ]) ->add('ville', TextType::class, [ 'label' => 'Ville *', 'label_attr' => [ "class" => "smaller lighter blue", "style" => "font-size: 21px;", ], ]); $formModifier = function (FormInterface $form, Region $region = null) { $ville = null === $region ? array() : $region->getNom(); $form->add('ville', EntityType::class, array( 'class' => 'GECandidatBundle:Ville', 'placeholder' => '', 'choices' => $ville, 'label' => 'Ville *', 'label_attr' => [ "class" => "smaller lighter blue", "style" => "font-size: 21px;", ], 'choice_label' => 'nom', 'multiple' => false, /*'query_builder' => function(VilleRepository $repository) { return $repository->getVilleByRegion(); }*/ )); }; $builder->addEventListener( FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) { $data = $event->getData(); $formModifier($event->getForm(), $data->getVille()); } ); $builder->get('region')->addEventListener( FormEvents::POST_SUBMIT, function (FormEvent $event) use ($formModifier) { $region = $event->getForm()->getData(); $formModifier($event->getForm()->getParent(), $region); } ); 

new.html.twig:

  {{ form_start(form) }} {{ form_row(form.region) }} {# <select id="ge_candidatbundle_annonce_region" ... #} {{ form_row(form.ville) }} {# <select id="ge_candidatbundle_annonce_ville" ... #} {# ... #} {{ form_end(form) }} <script> var $region = $('#ge_candidatbundle_annonce_region'); $region.change(function() { var $form = $(this).closest('form'); var data = {}; data[$region.attr('nom')] = $region.val(); $.ajax({ url : $form.attr('action'), type: $form.attr('method'), data : data, success: function(html) { $('#ge_candidatbundle_annonce_ville').replaceWith( $(html).find('#ge_candidatbundle_annonce_ville') ); } }); }); </script> 

Многие решения:

Более простым должно быть добавление villes в ваш объект Region и сделать что-то вроде этого:

 class Region { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="nom", type="string", length=255) */ private $nom; /** * @var int * * @ORM\Column(name="numero", type="smallint") */ private $numero; /** @ORM\OneToMany(targetEntity="Ville", inversedBy="region") **/ protected $villes; public function getVilles() { return $this->villes; } public function setVilles($villes) { $this->villes = $villes; return $this; } // [... + get/setVilles functions ...] } 

И в вашем типе:

 $formModifier = function (FormInterface $form, Region $region = null) { $villes = null === $region ? array() : $region->getVilles(); $form->add('ville', EntityType::class, array( 'class' => 'GECandidatBundle:Ville', 'placeholder' => '', 'choices' => $villes, 'label' => 'Ville *', 'label_attr' => [ "class" => "smaller lighter blue", "style" => "font-size: 21px;", ], 'choice_label' => 'nom', 'multiple' => false, /*'query_builder' => function(VilleRepository $repository) { return $repository->getVilleByRegion(); }*/ )); }; $builder->addEventListener( FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) { $data = $event->getData(); $formModifier($event->getForm(), $data->getVille()); } ); $builder->get('region')->addEventListener( FormEvents::POST_SUBMIT, function (FormEvent $event) use ($formModifier) { $region = $event->getForm()->getData(); $formModifier($event->getForm()->getParent(), $region); } ); 

Второй вариант:

раскомментируйте свой конструктор запросов и VilleRepository в свой VilleRepository ваш getVilleByRegion , передав аргумент субъекту region

ОБНОВИТЬ

Вы устанавливаете свои данные ajax с помощью несуществующего атрибута nom вместо кода javascript:

 <script> var $region = $('#ge_candidatbundle_annonce_region'); $region.change(function() { var $form = $(this).closest('form'); var data = {}; data[$region.attr('name')] = $region.val(); $.ajax({ url : $form.attr('action'), type: $form.attr('method'), data : data, success: function(html) { $('#ge_candidatbundle_annonce_ville').replaceWith( $(html).find('#ge_candidatbundle_annonce_ville') ); } }); }); </script> 

ОБНОВИТЬ

  1. Я изменил объекты.

  2. Я модифицировал AnnonceType.

  3. Я изменил new.html.twig.

Вот код для объектов:

Регион:

 class Region { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="nom", type="string", length=255) */ private $nom; /** * @var int * * @ORM\Column(name="numero", type="smallint") */ private $numero; /** * @ORM\OneToMany(targetEntity="GE\CandidatBundle\Entity\Ville", mappedBy="region") **/ protected $villes; /** * Get villes * * @return \Doctrine\Common\Collections\Collection */ public function getVilles() { return $this->villes; } } 

Ville Entity:

 class Ville { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="nom", type="string", length=255) */ private $nom; /** * @var int * * @ORM\Column(name="numero", type="smallint") */ private $numero; /** * @var int * * @ORM\Column(name="codePostal", type="smallint") */ private $codePostal; /** * @var Region * @ORM\ManyToOne(targetEntity="GE\CandidatBundle\Entity\Region", inversedBy="villes") */ protected $region; } 

AnnonceType:

  $builder ->add('region', EntityType::class, [ 'label' => 'Region *', 'label_attr' => [ "class" => "smaller lighter blue", "style" => "font-size: 21px;", ], 'class' => 'GECandidatBundle:Region', 'choice_label' => 'nom', 'multiple' => false, 'query_builder' => function(RegionRepository $repository) { return $repository->getListeRegion(); } ]) ->add('ville'); $formModifier = function (FormInterface $form, Region $region = null) { $villes = null === $region ? array() : $region->getVilles(); $form->add('ville', EntityType::class, array( 'class' => 'GECandidatBundle:Ville', 'placeholder' => '', 'choices' => $villes, 'label' => 'Ville *', 'label_attr' => [ "class" => "smaller lighter blue", "style" => "font-size: 21px;", ], 'choice_label' => 'nom', 'multiple' => false, )); }; $builder->addEventListener( FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) { $data = $event->getData(); $formModifier($event->getForm(), $data->getVille()); } ); $builder->get('region')->addEventListener( FormEvents::POST_SUBMIT, function (FormEvent $event) use ($formModifier) { $region = $event->getForm()->getData(); $formModifier($event->getForm()->getParent(), $region); } ); 

new.html.twig:

  {{ form_start(form) }} {{ form_row(form.region) }} {# <select id="ge_candidatbundle_annonce_region" ... #} {{ form_row(form.ville) }} {# <select id="ge_candidatbundle_annonce_ville" ... #} {# ... #} {{ form_end(form) }} <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script> var $region = $('#ge_candidatbundle_annonce_region'); $region.change(function() { var $form = $(this).closest('form'); var data = {}; data[$region.attr('name')] = $region.val(); $.ajax({ url : $form.attr('action'), type: $form.attr('method'), data : data, success: function(html) { $('#ge_candidatbundle_annonce_ville').replaceWith( $(html).find('#ge_candidatbundle_annonce_ville') ); } }); }); </script>