2012-04-12 35 views
28

我有以下字段和關聯商家實體: -如何在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; 

標籤和分類也有一個多對多的映射。 所以我們有Tag_Category,Merchant_Tag,Merchant_Category映射表。

現在我想對這些字段執行一些ajax。

我想讓用戶先選擇主標籤。在主標籤的基礎上,ajax將類別刷新爲僅屬於此標籤的類別和一些更多的操作。

我該如何做到這一點?

謝謝!

回答

55

我幾個月前就能完成這項工作。而a.aitboudad所分享的是準確的。第一次與Symfony/Sonata合作的人可能會遇到一些困難。

以下是這些步驟。

1> Extend Sonata CRUD的edit.html.twig/base_edit.html.twig 爲了簡單起見,我只使用後者。 複製vendor/bundles/Sonata/AdminBundle/Resources/views/CRUD/base_edit.html.twig到views文件夾對應MerchantAdminController - 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請求 我們主要是想獲得對應於特定的標籤類別ID列表的動作。但很可能你只是在使用索納塔的CRUD控制器。

定義您MerchantAdminController延伸CRUDController

<?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

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] 

使用這個新創建的控制器,而不是默認CRUDController注意第三個參數是你的控制器的名字。默認情況下它會是空的。

3.3> - 在您的控制器中創建一個名爲getCategoryOptionsFromTagAction的動作。您的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:如何獲得追加到所有索納塔元素的唯一ID

解決方案:使用admin變量這將使您可以訪問所有管理類的屬性,包括uniqId。查看如何使用它的代碼。

疑難雜症2:如何讓你的JS路由器。

解決方案:默認情況下,Symfony2的路由不JS工作。您需要使用名爲FOSJSRouting的套件(如上所述)並展示路線。這將使您可以訪問JS內的路由器對象。

我稍微修改了我的解決方案以使此示例更清晰。如果您發現有任何問題,請隨時發表評論。

+0

GRE在答案,很好的細節,不錯的一個!一個問題 - 爲什麼你需要在你的ajax調用中使用FOSJSRouting?將tagId作爲ajax發佈請求的一部分傳遞起來會不會很容易?這樣你可以避免加載額外的軟件包 – lopsided 2012-06-19 15:04:57

+3

謝謝兄弟,FOSJSRouting是訪問路由器對象(Routing.generate(...))來生成路徑的路徑。如果它是一個普通的PHP項目,我們只需要提供文件名 - categories_from_tag.php。但是我們需要在控制器中調用一個動作。 – Amit 2012-06-20 05:11:23

+3

我這樣做的方式是在我的Admin類(TagAdmin)中添加路由:'$ collection-> add('addToGroup',$ this-> getRouterIdParameter()。'/ addToGroup');',使用此路由ajax url like:'url:'{{admin.generateUrl('addToGroup',{'id':object.id})}'',用ajax定義中的extra數據參數:'data:'group = '+ $(this).prevAll('。group-id')。val(),' – lopsided 2012-06-20 08:23:49

4

在阿米特和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. 
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,以保持管理類的清潔劑越多越好:在塊的JavaScript

// 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]] 
2

,你必須改變"liszt:updated""chosen:updated"

希望它可以幫助別人;)

+0

歡迎來到SO :)你應該避免在答案中提出一個新的問題。要麼使用評論或打開一個新的問題。 – 2016-06-24 10:12:24

+0

thx @IvanGabriele和我已經編輯我的答案;) – 2016-06-24 13:09:52

相關問題