对于我的一个对象,我需要创建一些动态表单渲染...但我无法弄清楚如何在Sonata Admin中执行此操作。例如,当我创建一个对象时,我有一个字段类型。在这个字段中,我选择了一个我的对象将要成为的类型。现在当我根据类型选择我想要显示字段的类型时。例如,如果我选择“Carousel”类型,我想显示一个选择所有对象表单实体Gallery的字段。如果我选择“产品”类型,我想显示所有产品的字段以便从中选择...我该怎么做?
现在我有这个:
/**
* @param FormMapper $formMapper
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('Module', array(
'class' => 'col-md-6'
))
->add('position')
->add('type', null, array(
'attr' => array('class' => 'module_type')
))
->add('items', 'entity', array(
'class' => 'ApplicationSonataMediaBundle:Gallery'
))
->end()
;
}
我已经覆盖了编辑模板:
{% extends 'SonataAdminBundle:CRUD:edit.html.twig' %}
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
$(document).ready(function () {
$(".module_type").change(function() {
});
});
</script>
{% endblock %}
正如你所看到的,画廊现在是硬编码的。
我现在无法弄清楚如何执行此操作...如何说如果选择的值是这个,请在字段中使用该实体...问题是在Sonata中呈现表单的方式非常复杂..我不明白..
也许我应该使用ajax?但是,当我发送一个值并获得响应时如何添加一个字段而不刷新?
任何帮助表示感谢。
答案 0 :(得分:2)
Sonata为您提供了'sonata_type_choice_field_mask&#39;类型允许您根据此参数的值来动态更改表单上显示的字段&#39; sonata_type_choice_field_mask&#39;输入所以你不必使用ajax。
Here is the doc您可以在其中找到有关奏鸣曲类型和选择字段掩码的所有内容。
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('type', 'sonata_type_choice_field_mask', array(
'choices' => array(
//The list of available 'Type' here
'choice1',
'choice2'
),
'map' => array(
//What you want to display depending of the selected option
'choice1' => array(
// List of the fields displayed if choice 1 is selected
'field1', 'field3'
),
'choice2' => array(
// List of the fields displayed if choice 2 is selected
'field2', 'field3'
)
),
'placeholder' => 'Choose an option',
'required' => true
))
->add('field1', 'entity', array(/* Options for entity1 goes here */))
->add('field2', 'entity', array(/* Options for entity2 goes here */))
->add('field3')
;
}
答案 1 :(得分:1)
如果我真的了解你的需要你当然必须使用ajax,首先你需要向这个EntityAdminController添加新的管理路由来执行它,你必须覆盖configureRoutes方法并添加你的新路由:
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('reloadCities', 'realod-cities');
}
然后你必须创建一个新的控制器,它将为你的新路线设置动作定义,如:
use Sonata\AdminBundle\Controller\CRUDController as BaseController;
class CitiesController extends BaseController
{
public function reloadCitiesAction()
{
// some code
return $this->render(...);
}
}
然后你必须覆盖SonataAdminBundle:CRUD:edit.html.twig
模板并设置你的javascript事件监听器:
{% extends 'SonataAdminBundle:CRUD:edit.html.twig' %}
{% block form %}
{{ parent() }}
<script type="text/javascript">
$(document).ready(function () {
countries.change(function () {
$.ajax({
url: "{{ admin.generateUrl('reloadCities') }}",
data: {
'id': $(this).val(),
'uniquid': '{{ admin.uniqid }}'
},
method: 'POST',
success: function (html) {
// code...
},
error: function (data) {
// more code
}
});
});
});
</script>
答案 2 :(得分:0)
在进行了永久性的研究以找到一种使用symfony4的ajax和sonata使用动态下拉菜单的方法之后,我想分享我的解决方案对我的实际作用。
就我而言,我有一个地区,这个地区有不同的城市。我有一家公司,首先选择一个地区,然后再选择该地区的城市。
我做了什么:
为地区创建实体
为城市创建实体
进入您的主类(在我的情况下,这是公司实体,并为地区和城市添加两个实体
/**
* @ORM\ManyToOne(targetEntity="App\Wdm\MainBundle\Entity\Model\Cities", inversedBy="id")
*/
private $city;
/**
* @ORM\ManyToOne(targetEntity="App\Wdm\MainBundle\Entity\Model\Districts", inversedBy="id")
*/
private $district;
更新数据库架构,并使用一些示例数据填充城市和地区字段
在configureFormFields函数中进入AdminClass并添加以下内容(请确保将'choice_label'选项与您所在地区或城市实体中的相应字段正确使用。
protected function configureFormFields(FormMapper $formMapper)
{ $formMapper
// Some other added fields
->add('district', EntityType::class, [
'choice_label' => 'name',
'class' => Districts::class,
'placeholder' => '',
])
->add('city', EntityType::class, [
'choice_label' => 'name',
'class' => Cities::class,
'placeholder' => '',
])
;
这应该已经可以很好地工作了。您现在应该可以有一个从属字段。现在让我们来看看AJAX魔术。
进入您的AdminClass(与configureFields-Class相同)并添加以下内容
protected function configureRoutes(RouteCollection $collection)
{ $collection->add('reloadCities', 'reload-cities');
}
<?php
namespace App\Wdm\MainBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sonata\AdminBundle\Controller\CRUDController as BaseController;
use App\Wdm\MainBundle\Entity\Model\Cities;
class CitiesController extends BaseController
{
public function reloadCitiesAction(Request $request)
{ $districtid = $request->request->get('id');
$cities = $this->getDoctrine()->getRepository(Cities::class)->findBy(array("district" => $districtid));
return $this->render("company/cities.html.twig", array("cities" => $cities));
}
}
...并且不要忘记在您的services.yaml中注册此控制器...
admin.company:
class: App\Wdm\MainBundle\Admin\CompanyAdmin
arguments:
- ~
- App\Wdm\MainBundle\Entity\Model\Company
- App\Wdm\MainBundle\Controller\CitiesController (THIS IS THE NEW ROW)
...最后是在此函数中调用的小模板...
// THIS IS THE cities.html.twig
{% for city in cities %}
<option value="{{ city.id }}">{{ city.name }}</option>
{% endfor %}
进入您的AdminClass并插入以下代码(例如,在configureFormFields之前)
public function getTemplate($name)
{
switch ($name) {
case 'edit':
return 'company/cities_admin.html.twig';
break;
default:
return parent::getTemplate($name);
break;
}
}
现在,我们将创建覆盖默认模板的city_admin.html.twig模板
{% extends 'SonataAdminBundle:CRUD:edit.html.twig' %}
{% block form %}
{{ parent() }}
<script type="text/javascript">
$(document).ready(function () {
$("#ID_OF_YOUR_DISTRICT_SELECT_FIELD").change(function () {
$.ajax({
url: "{{ admin.generateUrl('reloadCities') }}",
data: {
'id': $(this).val(),
'uniquid': '{{ admin.uniqid }}'
},
method: 'POST',
success: function (html) {
$("#ID_OF_YOUR_CITY_SELECT_FIELD").html(html);
},
error: function (data) {
// more code
}
});
});
});
</script>
{% endblock %}
就是这样。应该像魅力一样工作。
答案 3 :(得分:0)
我对您的代码有一个疑问:url: "{{ admin.generateUrl('reloadCities') }}",
如果我错了,请告诉我,但是变量admin
可以调用,这要感谢模板扩展:{% extends 'SonataAdminBundle:CRUD:edit.html.twig' %}
仅当我扩展模板时,出现此错误:
变量“ base_template”不存在。
有什么想法吗?