我有一个商家实体,其中包含以下字段和关联: -
/**
* @ORM\ManyToMany(targetEntity="Category", inversedBy="merchants")
*/
public $categories;
/**
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="merchants")
*/
public $tags;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="merchants")
*/
protected $primaryCategory;
/**
* @ORM\ManyToOne(targetEntity="Tag", inversedBy="merchants")
*/
protected $primaryTag;
标签和类别也有ManyToMany映射。 所以我们有Tag_Category,Merchant_Tag,Merchant_Category映射表。
现在我想在这些字段上执行一些ajax。
我想让用户先选择主要标签。在主标记的基础上,ajax将类别刷新为仅属于此标记的类别以及更多操作。
我怎样才能做到这一点?
谢谢!
答案 0 :(得分:58)
几个月前我就能完成这项工作。虽然a.aitboudad分享的内容是准确的。 Symfony / Sonata的第一次定时器可能会面临一些问题。
以下是步骤。
<强> 1&GT;扩展Sonata CRUD的edit.html.twig
/ base_edit.html.twig
。
为简单起见,我只使用后者。
将vendor/bundles/Sonata/AdminBundle/Resources/views/CRUD/base_edit.html.twig
复制到与MerchantAdminController相对应的views文件夹中 - YourBundle/Resources/views/Merchant/base_edit.html.twig
<强> 2 - ;我们需要告诉MerchantAdmin类使用此模板。因此我们覆盖SonataAdmin的getEditTemplate
方法,如下所示:
public function getEditTemplate()
{
return 'YourBundle:Merchant:base_edit.html.twig';
}
3&gt; 接下来,我们需要在base_edit.html.twig
中对Ajax功能进行编码。标准Ajax包含以下内容:
3.1&gt; - 在控制器中为Ajax请求创建一个Action 我们主要想获得与特定标签相对应的类别ID列表。但很可能你只是使用Sonata的CRUD控制器。
定义扩展CRUDController的MerchantAdminController
<?php
namespace GD\AdminBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use GD\AdminBundle\Entity\Merchant;
class MerchantAdminController extends Controller
{
}
3.2&gt; - 通过YourBundle/Resources/config/services.yml
gd_admin.merchant:
class: %gd_admin.merchant.class%
tags:
- { name: sonata.admin, manager_type: orm, group: gd_merchant, label: Merchants }
arguments: [null, GD\AdminBundle\Entity\Merchant, GDAdminBundle:MerchantAdmin]
请注意,第3个参数是控制器的名称。默认情况下,它将为null。
3.3&gt; - 在控制器中创建名为getCategoryOptionsFromTagAction
的操作。您的Ajax调用将是此Action。
// route - get_categories_from_tag
public function getCategoryOptionsFromTagAction($tagId)
{
$html = ""; // HTML as response
$tag = $this->getDoctrine()
->getRepository('YourBundle:Tag')
->find($tagId);
$categories = $tag->getCategories();
foreach($categories as $cat){
$html .= '<option value="'.$cat->getId().'" >'.$cat->getName().'</option>';
}
return new Response($html, 200);
}
3.4&gt; - 在app/config/routing.yml
中创建相应的路线。如果你正在使用FOSJsRoutingBundle,请记住暴露你的路线(否则你必须硬编码,这不是一个好主意)。
get_categories_from_tag:
pattern: /{_locale}/admin/gd/admin/merchant/get-categories-from-tag/{tagId}
defaults: {_controller: GDAdminBundle:MerchantAdmin:getCategoryOptionsFromTag}
options:
expose: true
3.5&gt; - 发出Ajax请求并使用响应
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
$(document).ready(function(){
var primaryTag = $("#{{ admin.uniqId }}_primaryTag");
primaryTag.change(updateCategories()); // Bind the function to updateCategories
primaryTag.change(); // Manual trigger to update categories in Document load.
function updateCategories(){
return function () {
var tagId = $("#{{ admin.uniqId }}_primaryTag option:selected").val();
var primaryCategory = $("#{{ admin.uniqId }}_primaryCategory");
primaryCategory.empty();
primaryCategory.trigger("liszt:updated");
var locale = '{{ app.request.get('_locale') }}';
var objectId = '{{ admin.id(object) }}'
var url = Routing.generate('get_categories_from_tag', { '_locale': locale, 'tagId': tagId, _sonata_admin: 'gd_admin.merchant', id: objectId });
$.post(url, { tagId: tagId }, function(data){
primaryCategory.empty().append(data);
primaryCategory.trigger("liszt:updated");
},"text");
primaryCategory.val("option:first").attr("selected", true);
};
}
});
</script>
{% endblock %}
得知1: 如何获取附加到所有Sonata元素的唯一ID
解决方案: 使用admin变量可以访问所有Admin Class的属性,包括uniqId。请参阅有关如何使用它的代码。
得知2: 如何在JS中获取路由器。
解决方案: 默认情况下,Symfony2路由在JS中不起作用。您需要使用名为FOSJSRouting的包(如上所述)并公开路径。这样您也可以访问JS中的Router对象。
我稍微修改了我的解决方案,使这个例子更加清晰。如果您发现任何错误,请随时发表评论。
答案 1 :(得分:4)
在Amit和Lumbendil的第1步回答你应该改变
{% extends base_template %}
进入
{% extends 'SonataAdminBundle::standard_layout.html.twig' %}
如果您收到类似
的错误Unable to find template "" in YourBundle:YourObject:base_edit.html.twig at line 34.
答案 2 :(得分:4)
非常详细的帖子,只是为了更新覆盖方式并使用Admin类中的编辑模板。
现在,你应该这样做:
// src/AppBundle/Admin/EntityAdmin.php
class EntityAdmin extends Admin
{
public function getTemplate($name)
{
if ( $name == "edit" )
{
// template 'base_edit.html.twig' placed in app/Resources/views/Entity
return 'Entity/base_edit.html.twig' ;
}
return parent::getTemplate($name);
}
}
或者将其注入使用provided method的服务定义中,以使Admin类尽可能清洁:
// app/config/services.yml
app.admin.entity:
class: AppBundle\Admin\EntityAdmin
arguments: [~, AppBundle\Entity\Entity, ~]
tags:
- {name: sonata.admin, manager_type: orm, group: "Group", label: "Label"}
calls:
- [ setTemplate, [edit, Entity/base_edit.html.twig]]
答案 3 :(得分:2)
,您必须将"liszt:updated"
更改为"chosen:updated"
希望它可以帮助某人;)