小编典典

如何在Sonata Admin表单中使用Ajax?

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。

我想允许用户首先选择主要标签。在主要标签的基础上,ajax将类别刷新为仅属于该标签的类别,并进行其他一些操作。

我该如何实现?

谢谢!


阅读 240

收藏
2020-07-26

共1个答案

小编典典

几个月前,我能够完成这项工作。尽管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 >接下来,我们需要 编写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

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调用将与此操作有关。

// 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,请记住公开您的路线(否则,您必须进行硬编码,这不是一个好主意)。

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对象。

我对解决方案进行了一些修改,以使此示例更加清晰。如果您发现任何错误,请随时发表评论。

2020-07-26