Symfony5 Form multiple select (choices list) data auto-update with AJAX
Symfony5 Form multiple select (choices list) data auto-update with AJAX
我有一个包含三个“select”(选择列表)的位置表单:国家、地区和部门。这些“select”默认包含国家、地区和部门的所有列表。我想让我的用户先选择国家或地区或部门。
我想做的事情:
当用户选择一个国家时,地区数据会随之改变。地区和部门之间相同。
我有:
- 当我先选择一个国家然后选择一个地区时,数据自动更新在国家和地区之间起作用但是对于地区到部门,AJAX 请求未启动。
- 但是如果我直接选择一个区域然后启动AJAX请求但是它不会更新部门[=39=中的数据].
- 但是,在表格中,当我评论有关国家和地区自动更新的部分时,启动了 AJAX 请求,并且地区和部门之间的自动更新工作。
这是我的表格:
//src/Form/LocationType.php
class LocationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('country', EntityType::class, [
'class' => Country::class,
])
->add('area', EntityType::class, [
'class' => Area::class,
'required' => false
])
->add('department', EntityType::class, [
'class' => Department::class,
'required' => false
]);
//The part I comment for makes the auto-update between area and department works
$formArea = function(FormInterFace $form, Country $country = null) {
if($country === null) {
$form->add('area', EntityType::class, [
'class' => Area::class,
'required' => false
]);
}
else {
$areas = $country->getAreas();
$form->add('area', EntityType::class, [
'class' => Area::class,
'choices' => $areas,
'required' => false
]);
}
};
$builder->get('country')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formArea){
$country = $event->getForm()->getData();
$formArea($event->getForm()->getParent(), $country);
}
);
//
$formDepartment = function(FormInterFace $form, Area $area = null) {
if($area === null) {
$form->add('department', EntityType::class, [
'class' => Department::class,
'required' => false
]);
}
else {
$departments = $area->getDepartments();
$form->add('department', EntityType::class, [
'class' => Department::class,
'choices' => $departments,
'required' => false
]);
}
};
$builder->get('area')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formDepartment){
$area = $event->getForm()->getData();
$formDepartment($event->getForm()->getParent(), $area);
}
);
}
和 AJAX 调用的 JS 代码:
//assets/js/selectCountryAreaDepartment.js
window.onload = () => {
let country = document.querySelector("#location_country");
country.addEventListener("change", function() {
let form = this.closest("form");
let data = this.name + "=" + this.value;
console.log(data);
fetch(form.action, {
method: form.getAttribute("method"),
body: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let content = document.createElement("html");
content.innerHTML = html;
let area = content.querySelector("#location_area");
document.querySelector("#location_area").replaceWith(area);
console.log(area);
})
.catch(error => {
console.log(error);
})
});
let area = document.querySelector("#location_area");
area.addEventListener("change", function() {
let formArea = this.closest("form");
let dataArea = this.name + "=" + this.value;
//console.log(formArea);
console.log(dataArea);
fetch(formArea.action, {
method: formArea.getAttribute("method"),
body: dataArea,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let contentArea = document.createElement("html");
contentArea.innerHTML = html;
let department = contentArea.querySelector("#location_department");
document.querySelector("#location_department").replaceWith(department);
console.log(department);
})
.catch(error => {
console.log(error);
})
});
}
此代码基于此法语教程:https://www.youtube.com/watch?v=f7tdb30evUk
通过删除 add() 在 formModifiers formArea 和 formDepartment 它避免在使用另一个 select 时“重置”select:
//src/Form/LocationType.php
// …
// formModifier
$formArea = function(FormInterFace $form, LocationCountry $country = null) {
if($country != null)
{
$areas = $country->getAreas();
$form->add('area', EntityType::class, [
'class' => LocationArea::class,
'choices' => $areas,
'placeholder' => 'select now an area',
'required' => false
]);
}
};
$builder->get('country')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formArea){
$country = $event->getForm()->getData();
$formArea($event->getForm()->getParent(), $country);
}
);
// formModifier
$formDepartment = function(FormInterFace $form, LocationArea $area = null) {
if($area != null)
{
$departments = $area->getDepartments();
$form->add('department', EntityType::class, [
'class' => LocationDepartment::class,
'choices' => $departments,
'placeholder' => 'select now a department',
'required' => false,
'choice_label' => function ($departments) {
return '['.$departments->getCode().']-'.$departments->getName();
}
]);
}
};
更新区select删除了area.addEventListener
,所以需要re-activate更新区select后的eventListener,所以我创建了一个函数area_addEnventListener()
window.onload = () => {
let country = document.querySelector("#location_country");
country.addEventListener("change", function() {
let form = this.closest("form");
let data = this.name + "=" + this.value;
fetch(form.action, {
method: form.getAttribute("method"),
body: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let content = document.createElement("html");
content.innerHTML = html;
let area = content.querySelector("#location_area");
document.querySelector("#location_area").replaceWith(area);
area_addEnventListener(area);
})
.catch(error => {
console.log(error);
})
});
let area = document.querySelector("#location_area");
area_addEnventListener(area);
}
function area_addEnventListener(area_select) {
area_select.addEventListener("change", function() {
let formArea = area_select.closest("form");
let dataArea = area_select.name + "=" + area_select.value;
fetch(formArea.action, {
method: formArea.getAttribute("method"),
body: dataArea,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let contentArea = document.createElement("html");
contentArea.innerHTML = html;
let department = contentArea.querySelector("#location_department");
document.querySelector("#location_department").replaceWith(department);
})
.catch(error => {
console.log(error);
})
});
}
我有一个包含三个“select”(选择列表)的位置表单:国家、地区和部门。这些“select”默认包含国家、地区和部门的所有列表。我想让我的用户先选择国家或地区或部门。
我想做的事情:
当用户选择一个国家时,地区数据会随之改变。地区和部门之间相同。
我有:
- 当我先选择一个国家然后选择一个地区时,数据自动更新在国家和地区之间起作用但是对于地区到部门,AJAX 请求未启动。
- 但是如果我直接选择一个区域然后启动AJAX请求但是它不会更新部门[=39=中的数据].
- 但是,在表格中,当我评论有关国家和地区自动更新的部分时,启动了 AJAX 请求,并且地区和部门之间的自动更新工作。
这是我的表格:
//src/Form/LocationType.php
class LocationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('country', EntityType::class, [
'class' => Country::class,
])
->add('area', EntityType::class, [
'class' => Area::class,
'required' => false
])
->add('department', EntityType::class, [
'class' => Department::class,
'required' => false
]);
//The part I comment for makes the auto-update between area and department works
$formArea = function(FormInterFace $form, Country $country = null) {
if($country === null) {
$form->add('area', EntityType::class, [
'class' => Area::class,
'required' => false
]);
}
else {
$areas = $country->getAreas();
$form->add('area', EntityType::class, [
'class' => Area::class,
'choices' => $areas,
'required' => false
]);
}
};
$builder->get('country')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formArea){
$country = $event->getForm()->getData();
$formArea($event->getForm()->getParent(), $country);
}
);
//
$formDepartment = function(FormInterFace $form, Area $area = null) {
if($area === null) {
$form->add('department', EntityType::class, [
'class' => Department::class,
'required' => false
]);
}
else {
$departments = $area->getDepartments();
$form->add('department', EntityType::class, [
'class' => Department::class,
'choices' => $departments,
'required' => false
]);
}
};
$builder->get('area')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formDepartment){
$area = $event->getForm()->getData();
$formDepartment($event->getForm()->getParent(), $area);
}
);
}
和 AJAX 调用的 JS 代码:
//assets/js/selectCountryAreaDepartment.js
window.onload = () => {
let country = document.querySelector("#location_country");
country.addEventListener("change", function() {
let form = this.closest("form");
let data = this.name + "=" + this.value;
console.log(data);
fetch(form.action, {
method: form.getAttribute("method"),
body: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let content = document.createElement("html");
content.innerHTML = html;
let area = content.querySelector("#location_area");
document.querySelector("#location_area").replaceWith(area);
console.log(area);
})
.catch(error => {
console.log(error);
})
});
let area = document.querySelector("#location_area");
area.addEventListener("change", function() {
let formArea = this.closest("form");
let dataArea = this.name + "=" + this.value;
//console.log(formArea);
console.log(dataArea);
fetch(formArea.action, {
method: formArea.getAttribute("method"),
body: dataArea,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let contentArea = document.createElement("html");
contentArea.innerHTML = html;
let department = contentArea.querySelector("#location_department");
document.querySelector("#location_department").replaceWith(department);
console.log(department);
})
.catch(error => {
console.log(error);
})
});
}
此代码基于此法语教程:https://www.youtube.com/watch?v=f7tdb30evUk
通过删除 add() 在 formModifiers formArea 和 formDepartment 它避免在使用另一个 select 时“重置”select:
//src/Form/LocationType.php
// …
// formModifier
$formArea = function(FormInterFace $form, LocationCountry $country = null) {
if($country != null)
{
$areas = $country->getAreas();
$form->add('area', EntityType::class, [
'class' => LocationArea::class,
'choices' => $areas,
'placeholder' => 'select now an area',
'required' => false
]);
}
};
$builder->get('country')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formArea){
$country = $event->getForm()->getData();
$formArea($event->getForm()->getParent(), $country);
}
);
// formModifier
$formDepartment = function(FormInterFace $form, LocationArea $area = null) {
if($area != null)
{
$departments = $area->getDepartments();
$form->add('department', EntityType::class, [
'class' => LocationDepartment::class,
'choices' => $departments,
'placeholder' => 'select now a department',
'required' => false,
'choice_label' => function ($departments) {
return '['.$departments->getCode().']-'.$departments->getName();
}
]);
}
};
更新区select删除了area.addEventListener
,所以需要re-activate更新区select后的eventListener,所以我创建了一个函数area_addEnventListener()
window.onload = () => {
let country = document.querySelector("#location_country");
country.addEventListener("change", function() {
let form = this.closest("form");
let data = this.name + "=" + this.value;
fetch(form.action, {
method: form.getAttribute("method"),
body: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let content = document.createElement("html");
content.innerHTML = html;
let area = content.querySelector("#location_area");
document.querySelector("#location_area").replaceWith(area);
area_addEnventListener(area);
})
.catch(error => {
console.log(error);
})
});
let area = document.querySelector("#location_area");
area_addEnventListener(area);
}
function area_addEnventListener(area_select) {
area_select.addEventListener("change", function() {
let formArea = area_select.closest("form");
let dataArea = area_select.name + "=" + area_select.value;
fetch(formArea.action, {
method: formArea.getAttribute("method"),
body: dataArea,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset:UTF-8"
}
})
.then(response => response.text())
.then(html => {
let contentArea = document.createElement("html");
contentArea.innerHTML = html;
let department = contentArea.querySelector("#location_department");
document.querySelector("#location_department").replaceWith(department);
})
.catch(error => {
console.log(error);
})
});
}