我有一个具有以下字段和关联的商家实体:-
/** * @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将类别刷新为仅属于该标签的类别,并进行其他一些操作。
我该如何实现?
谢谢!
几个月前,我能够完成这项工作。尽管a.aitboudad分享的是准确的。Symfony / Sonata的初学者可能会遇到一些陷阱。
步骤如下。
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
edit.html.twig
base_edit.html.twig
vendor/bundles/Sonata/AdminBundle/Resources/views/CRUD/base_edit.html.twig
YourBundle/Resources/views/Merchant/base_edit.html.twig
**2
我们需要告诉我们的MerchantAdmin类使用此模板。**因此,我们重写了SonataAdmin的getEditTemplate方法,如下所示:
getEditTemplate
public function getEditTemplate() { return 'YourBundle:Merchant:base_edit.html.twig'; }
3 >接下来,我们需要 编写Ajax功能 在我们的base_edit.html.twig。标准Ajax包括以下内容:
3.1 > -在控制器中为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 > -通过在中定义它,告诉您的Admin服务使用此新创建的控制器而不是默认的CRUDControllerYourBundle/Resources/config/services.yml
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]
请注意,第三个参数是控制器的名称。默认情况下,它应该为null。
3.3 > - getCategoryOptionsFromTagAction在控制器中创建一个名为Action的动作。您的Ajax调用将与此操作有关。
getCategoryOptionsFromTagAction
// 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,请记住公开您的路线(否则,您必须进行硬编码,这不是一个好主意)。
app/config/routing.yml
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请求并使用响应
{% 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 Routing在JS中不起作用。您需要使用一个名为FOSJSRouting的包(如上所述)并公开路由。这也将使您能够访问JS中的Router对象。
我对解决方案进行了一些修改,以使此示例更加清晰。如果您发现任何错误,请随时发表评论。