如何在Sonata Admin窗体中使用Ajax?
我有一个商家实体与以下领域和协会: –
/** * @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。
我想让用户先select主标签。 在主标签的基础上,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
2>我们需要告诉我们的MerchantAdmin类使用这个模板。 所以我们重写SonataAdmin的getEditTemplate
方法如下:
public function getEditTemplate() { return 'YourBundle:Merchant:base_edit.html.twig'; }
3>接下来,我们需要在base_edit.html.twig
编写Ajaxfunction 。 标准Ajax包含以下内容:
3.1>在Ajax请求的控制器中创build一个Action我们主要想获得一个与特定标签对应的类别ID列表。 但最有可能的是你只是使用索纳塔的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> – 通过在YourBundle/Resources/config/services.yml
定义它来告诉你的Admin服务使用这个新创build的控制器而不是默认的CRUDController
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>在控制器中创build一个名为getCategoryOptionsFromTagAction
的Action。 你的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> – 在app/config/routing.yml
创build相应的路由。 如果你正在使用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> – 创buildAjax请求并使用响应
{% 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
解决scheme:使用adminvariables可以访问所有Admin类的属性,包括uniqId。 查看如何使用它的代码。
问题2:如何让你的JS中的路由器。
解决scheme:默认情况下,Symfony2 Routing在JS中不起作用。 您需要使用一个名为FOSJSRouting的包(如上所述)并显示路由。 这会让你访问你的JS中的路由器对象。
我稍微修改了我的解决scheme,使这个例子更清晰。 如果您发现任何错误,请随时发表评论。
在Amit和Lumbendil答案的第一步,你应该改变
{% extends base_template %}
成
{% extends 'SonataAdminBundle::standard_layout.html.twig' %}
如果你得到一个错误
Unable to find template "" in YourBundle:YourObject:base_edit.html.twig at line 34.
非常详细的post,只是为了更新覆盖的方式,并使用pipe理类中的编辑模板。
现在,你应该这样做:
// 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); } }
或者使用提供的方法将其注入到服务定义中,以尽可能保持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]]
在JavaScript块,你必须改变"liszt:updated"
为"chosen:updated"
希望它能帮助别人;)