Comment utiliser Ajax dans les formulaires Admin Sonata?

j'ai un Marchand entité avec les champs suivants et d'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;

les Tags et les catégories ont aussi une cartographie ManyToMany. Donc nous avons Tag_Category, Merchant_Tag, Merchant_Category tables de cartographie.

maintenant je veux effectuer un peu d'ajax sur ces champs.

je veux permettre à l'utilisateur de sélectionner la Primaire première Balise. Sur la base de la balise primaire, ajax rafraîchit les catégories à seulement ceux qui appartiennent à cette balise et certains plus opérations.

Comment puis-je y parvenir?

Merci!

29
demandé sur likeitlikeit 2012-04-12 10:57:52

4 réponses

j'ai pu faire ce travail il y a quelques mois. Pendant ce temps.aitboudad a partagé est exacte. Il y a quelques gotcha que les débutants avec Symfony/Sonata pourraient affronter.

Voici les étapes.

1> Étendre Sonate CRUD edit.html.twig/base_edit.html.twig . Par souci de simplicité, je n'utiliserai que ce dernier. Copie vendor/bundles/Sonata/AdminBundle/Resources/views/CRUD/base_edit.html.twig dans le dossier Vues correspondant au MerchantAdminController -YourBundle/Resources/views/Merchant/base_edit.html.twig

2>, Nous devons dire à nos Classe MerchantAdmin pour utiliser ce modèle. donc nous outrepassons Sonataadmin's getEditTemplate méthode comme ceci:

public function getEditTemplate()
{
    return 'YourBundle:Merchant:base_edit.html.twig';
}

3> Ensuite, nous devons coder la fonctionnalité Ajax notre base_edit.html.twig . L'Ajax Standard comprend les éléments suivants:

3.1> -- Créer une Action dans le contrôleur pour la requête Ajax Nous voulons principalement obtenir une liste des identificateurs de catégorie correspondant à une étiquette particulière. Mais très probablement vous êtes juste j'utilise le contrôleur CRUD de Sonata.

Définir votre MerchantAdminController qui s'étend 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> -- dites à votre service administrateur d'utiliser ce controller nouvellement créé au lieu du CRUDController par défaut en le définissant dans 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]

Notez que le 3ème argument est le nom de votre contrôleur. Par défaut, il aurait été nulle.

3.3> -- Créer une Action nommée getCategoryOptionsFromTagAction dans votre contrôleur. Votre appel Ajax sera à cette 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> -- Créer la route correspondante dans app/config/routing.yml. N'oubliez pas d'exposer votre itinéraire si vous utilisez le FOSJsRoutingBundle (sinon vous aurez à hardcode qui n'est pas une bonne idée).

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> -- Faire la Requête Ajax et l'utilisation de la réponse

{% 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 %}

Gotcha 1: comment obtenir L'ID Unique cela est ajouté à tous les éléments de Sonate

Solution: utilisez la variable admin qui vous donnera accès à toutes les propriétés de la classe Admin, y compris uniqId. Voir code sur la façon de l'utiliser.

Gotcha 2: comment obtenir le routeur dans votre JS.

Solution: par défaut Symfony2 Routing ne fonctionne pas dans JS. Vous devez utiliser un paquet appelé FOSJSRouting (expliqué ci-dessus) et exposer la route. Cela vous donnera également accès à L'objet routeur dans votre JS.

j'ai légèrement modifié ma solution pour clarifier cet exemple. Si vous remarquez quelque chose de mal, n'hésitez pas à commenter.

57
répondu Amit 2012-05-29 13:12:21

à l'étape 1 de la réponse Amit et Lumbendil vous devez changer

{% extends base_template %}

en

{% extends 'SonataAdminBundle::standard_layout.html.twig' %}

si vous obtenez une erreur comme

Unable to find template "" in YourBundle:YourObject:base_edit.html.twig at line 34.  
4
répondu Paul Prijs 2014-03-31 12:47:42

Très détaillée post, juste pour mettre à jour la façon de remplacer et d'utiliser le modifier template dans la classe Admin.

Maintenant, vous devez le faire de cette façon:

// 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);
    }
}

ou l'injecter dans la définition de service utilisé le méthode fournie, pour garder l'Administrateur de classe comme le plus propre possible:

// 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]]
4
répondu guillermogfer 2015-06-24 14:36:44

dans le bloc javascript, vous devez modifier "liszt:updated""chosen:updated"

j'espère que ça aide quelqu'un ;)

2
répondu Hibatallah Aouadni 2016-06-24 13:59:23