如何在 symfony 中动态填充下拉列表? (select 该地区的城市)
How to fill the dropdown list dynamically in symfony? (select the cities of the region)
我解释一下我的问题:
我必须创建一个表单,根据我们在之前的选择中填写下拉列表。
我有两个实体:
一个Region可以有多个Cities(ManyToOne)关系。
我按照这里的文档 How to Dynamically Modify Forms Using Form Events (Dynamic Generation for Submitted Forms) .
这是实体的代码:
区域实体:
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;
}
维尔实体:
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 选项检索区域列表,但是 如何根据区域选择检索城市列表。
公告类型:
$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);
}
);
第二个选项:
通过传入参数 region
实体
取消注释您的查询生成器并在 VilleRepository
您的 getVilleByRegion
中实施
更新
您使用不存在的属性设置 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>
更新
我修改了实体。
我修改了AnnonceType。
我修改了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;
}
}
维尔实体:
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;
}
公告类型:
$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>
我解释一下我的问题:
我必须创建一个表单,根据我们在之前的选择中填写下拉列表。
我有两个实体:
一个Region可以有多个Cities(ManyToOne)关系。
我按照这里的文档 How to Dynamically Modify Forms Using Form Events (Dynamic Generation for Submitted Forms) .
这是实体的代码:
区域实体:
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;
}
维尔实体:
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 选项检索区域列表,但是 如何根据区域选择检索城市列表。
公告类型:
$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);
}
);
第二个选项:
通过传入参数 region
实体
VilleRepository
您的 getVilleByRegion
中实施
更新
您使用不存在的属性设置 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>
更新
我修改了实体。
我修改了AnnonceType。
我修改了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;
}
}
维尔实体:
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;
}
公告类型:
$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>