问题描述
我有一个包含以下字段和关联的商家实体:-
I have a Merchant entity with the following fields and associations:-
/**
* @ORMManyToMany(targetEntity="Category", inversedBy="merchants")
*/
public $categories;
/**
* @ORMManyToMany(targetEntity="Tag", inversedBy="merchants")
*/
public $tags;
/**
* @ORMManyToOne(targetEntity="Category", inversedBy="merchants")
*/
protected $primaryCategory;
/**
* @ORMManyToOne(targetEntity="Tag", inversedBy="merchants")
*/
protected $primaryTag;
标签和类别也有一个多对多映射.所以我们有 Tag_Category、Merchant_Tag、Merchant_Category 映射表.
The Tags and Categories also have a ManyToMany mapping.So we have Tag_Category, Merchant_Tag, Merchant_Category mapping tables.
现在我想对这些字段执行一些ajax.
Now I want to perform some ajax on these fields.
我想让用户先选择主标签.ajax在Primary Tag的基础上,将category刷新为只属于这个Tag的类别,并进行一些操作.
I want to allow the user to select the Primary Tag first. On the basis of the Primary Tag, ajax refresh the categories to only those which belong to this Tag and some more operations.
我怎样才能做到这一点?
How can I achieve this?
谢谢!
推荐答案
几个月前我能够完成这项工作.而 a.aitboudad 分享的内容是准确的.第一次接触 Symfony/Sonata 的人可能会遇到一些问题.
I was able to make this work a few months back. While what a.aitboudad has shared is accurate. There are a few gotcha's that first timers with Symfony/Sonata might face.
这是步骤.
1> 扩展 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
1> Extend Sonata CRUD's edit.html.twig
/ base_edit.html.twig
.For simplicity, I'll use only the latter.Copy vendor/bundles/Sonata/AdminBundle/Resources/views/CRUD/base_edit.html.twig
into the views folder corresponding to the MerchantAdminController - YourBundle/Resources/views/Merchant/base_edit.html.twig
2> 我们需要告诉我们的 MerchantAdmin 类使用这个模板. 所以我们像这样覆盖 SonataAdmin 的 getEditTemplate
方法:
2> We need to tell our MerchantAdmin class to use this template. So we override SonataAdmin's getEditTemplate
method like this:
public function getEditTemplate()
{
return 'YourBundle:Merchant:base_edit.html.twig';
}
3> 接下来,我们需要在 base_edit.html.twig
中编写 Ajax 功能.标准 Ajax 包括以下内容:
3> Next we need to code the Ajax functionality in our base_edit.html.twig
. Standard Ajax comprises of the following:
3.1> -- 在控制器中为 Ajax 请求创建一个 Action我们主要想获得与特定标签相对应的类别 ID 列表.但很可能您只是在使用 Sonata 的 CRUD 控制器.
3.1> -- Create an Action in the controller for the Ajax requestWe primarily want to get a list of category IDs corresponding to a particular tag. But most likely you are just using Sonata's CRUD Controller.
定义扩展 CRUDController 的 MerchantAdminController
Define your MerchantAdminController which extends CRUDController
<?php
namespace GDAdminBundleController;
use SonataAdminBundleControllerCRUDController as Controller;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use GDAdminBundleEntityMerchant;
class MerchantAdminController extends Controller
{
}
3.2> -- 通过在 YourBundle/Resources/config/services.yml
中定义,告诉您的管理服务使用这个新创建的控制器而不是默认的 CRUDController/p>
3.2> -- Tell your Admin service to use this newly created controller instead of the default CRUDController by defining it in 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, GDAdminBundleEntityMerchant, GDAdminBundle:MerchantAdmin]
请注意,第三个参数是您的控制器的名称.默认情况下它会是空的.
Notice that the 3rd argument is the name of your controller. By default it would have been null.
3.3> -- 在您的控制器中创建一个名为 getCategoryOptionsFromTagAction
的操作.您的 Ajax 调用将针对此操作.
3.3> -- Create an Action named getCategoryOptionsFromTagAction
in your controller. Your Ajax call will be to this 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> -- 在app/config/routing.yml
中创建对应的路由.如果您使用 FOSJsRoutingBundle,请记住公开您的路线(否则您必须进行硬编码,这不是一个好主意).
3.4> -- Create the corresponding route in app/config/routing.yml
. Remember to expose your route if you are using the FOSJsRoutingBundle (else you'll have to hardcode which is not a good idea).
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> -- 发出 Ajax 请求并使用响应
3.5> -- Make the Ajax Request and use the response
{% 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:如何获取附加到所有奏鸣曲元素的唯一 ID
Gotcha 1: How to get the Unique ID that is appended to all Sonata elements
解决方案: 使用 admin 变量可以让您访问所有管理类的属性,包括 uniqId.请参阅有关如何使用它的代码.
Solution: Use the admin variable which will give you access to all the Admin Class's properties including uniqId. See code on how to use it.
问题 2: 如何在您的 JS 中获取路由器.
Gotcha 2: How to get the Router in your JS.
解决方案: 默认情况下,Symfony2 路由在 JS 中不起作用.您需要使用一个名为 FOSJSRouting 的包(如上所述)并公开路由.这也将使您可以访问 JS 中的 Router 对象.
Solution: By default Symfony2 Routing doesn't work in JS. You need to use a bundle called FOSJSRouting (explained above) and expose the route. This will give you access to the Router object within your JS too.
我稍微修改了我的解决方案,使这个例子更清晰.如果您发现任何错误,请随时发表评论.
I have modified my solution slightly to make this example clearer. If you notice anything wrong, please feel free to comment.
这篇关于如何在 Sonata Admin 表单中使用 Ajax?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!