vendredi 19 octobre 2012

[Symfony2] La requête AJAX

Voila un sujet qui m'a bien pris la tête quand j'en ai eu besoin. Voici un post qui va vous permettre d'utiliser une simple requête AJAX sous Symfony2 (ou autre avec un peu d'imagination) grâce à la librairie JQuery.

Tout d'abord vous devez faire appel à la librairie JQuery, dans votre template principal (Le template principale se trouve généralement dans /App/Resources/Views/). Vous placez la ligne qui fera appel à la librairie, entre <head> et </head> :

 
 

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js" type="text/javascript"></script>

 

En suite vous préparez le formulaire qui vas nous servir pour notre exemple, dans notre cas nous voulons remplir une liste déroulante vide par défaut grâce au choix fait sur une autre liste déroulante. Nous allons donc déclarer deux liste déroulante, la première qui contiendra une liste de choix à faire, ici une liste de pays, et une seconde liste déroulante vide, qu'on remplira avec une liste de ville selon le pays choisi dans la première liste déroulante :

Dans votre controller, créez un formulaire (cela fonctionne aussi avec les formulaire externalisé) :
 
 


$form = $this->createFormBuilder()

->add('pays', 'choice', array('choices' => array('fr' => 'France', 'ma' => 'Maroc' , 'es' => 'Espagne', 'uk' => 'Royaume Unis'), 'label' => 'Pays : '))
->add('ville', 'choice', array('empty_value' => '', 'required' => false, 'label' => 'Ville : ')) 
    ->getForm();
 

Pour la seconde liste déroulante, ne pas oublier de lui préciser que la liste doit être vide grâce à "
'empty_value' => ''".
 
Toujours dans le controller, nous allons créer la fonction qui va faire notre requête et remplir la liste déroulante avec la liste des ville du pays que nous avons sélectionné. Cette fonction va se comporter exactement comme les autres fonctions que l'on trouve dans notre controller, nous devons donc déclarer un chemin pour y accéder dans notre fichier routing.yml comme ceci : 

 

IsMektebPostBundle_ajaxrq:
    pattern:  /ajaxrq
    defaults: { _controller:IsMektebPostBundle:Controller:ajaxrq}
 

Dans notre controller, nous déclarons donc cette fonction (Ne pas oublier Action à le fin du nom de la fonction) :
 

public function ajaxrqAction() {
        //Déclarer un tableau de type Array
        $list_ville = array();
        $request = $this->container->get('request');
        
        //vérifier le type de la requête
        if ($this->container->get('request')->isXmlHttpRequest()) {
            
            //Récuperer le choix que vous fait dans la liste déroulante "Pays : "
            $id = $request->request->get('id');
            //Faire la requête pour récurer la liste des ville du pays sélectionné, grâce à leur "id" (fr, ma, es..), insérer ce résultat dans $villes  
            //Remplir la liste déroulante avec le résultat 
            foreach ($villes as $v) {
                $list_ville[$v->getId()] = $v->getNomVille();
            }
        }
        
        //Instancier une "réponse" grâce à l'objet "Response"
        $response = new Response(json_encode($list_ville));
       //Lui indiquer le type de format dans le quelle est envoyé la reponse
        $response->headers->set('Content-Type', 'application/json');
       //Retourner la tout à notre liste déroulante
        return $response;
    }
 

Voila pour le controller, maintenant allons dans notre page html (ou se trouvera le formulaire) pour lui indiquer de faire cette requête au moment ou nous avons faire notre choix de pays. Nous allons donc rajouter un petit morceau de code qui va se charger de détecter le changement de choix de notre liste pays, de récupérer ce choix et de faire appel à notre requête en lui donnant les informations nécessaire pour remplir notre liste de villes. Voici ce morceau de code avec les explications nécessaire :
 
<script>
            //#form_pays représente la liste déroulante des pays, on lui indique de lancer une fonction au changement de choix dans la liste déroulante grâce à ".change(...).
            $("#form_pays").change(function() {
                $.ajax({
                    //On lui indique le type d'envoie des informations
                    type: 'POST',
                    //On lui indique le chemin de la fonction
                    url:  '{{ path('IsMektebPostBundle_ajaxrq') }}',
                    //On lui donne la valeur du choix qu'on a fait, et id est la variable qui va contenir notre valeur, nous la retrouvons dans notre controller
                    data: 'id=' + $(this).val(),
                    //Enfin nous lui disons de remplir notre formulaire avec le resultat 
                    success: function(response)
                    {
                        $('#form_ville').find("option").remove();
                        $.each(response, function(i, item) {
                            $('#form_ville').append(new Option(item, i));
                        });
                    }
                }
            )});
  </script>

Il n'y a plus rien à ajouter, si vous avez des soucis, n'hésitez pas à laisser des commentaires afin que je puisse y répondre ou améliorer ce petit tuto. J’espère que cela vous auras aidé.


16 commentaires:

itokia a dit…

Bonjour,

Avant tout je tenais à vous remercier pour votre tuto qui m'aide grandement dans mon projet.

J'ai un problème de récupération des valeurs dans mon select.
Je récupère tout mon code Html.

Avez vous une idée svp?

Je suis sous symfony2.

Merci

Mekteb a dit…

Bonjour itokia,

Cela est un plaisir pour moi. Ton problème vient du select lors de la requête AJAX ?
Si oui alors c'est que tu a deux solution possiblie :
1) il te retourne une erreur sous forme html (regarde bien ce qu'il te retourne)
2) Tu met ton résultat entre deux mauvaise balise qui affiche ton résultat en brut.

Je pense que c'est l'une des deux solution, donne plus de détail si ce n'est pas ça.

itokia a dit…

Merci de ta réactivité :)

Je viens de vérifier ce que je récupère dans mon select (Ajax) avec un alert(response).

J'obtiens bien ma page en html.

Sinon sur mon select Ajax, j'ai ajouté class="AjaxDt" et pour récupérer les valeurs j'utilise ton code avec $(.'AjaxDt').append...
Je te communiquerais bien mon code mais ici ca me met impossible d'accepter votre text.

itokia a dit…

Je viens de vérifier avec la console de debug est c'est bien le controler qui me retourne le cote html dans response.

Mekteb a dit…

C'est ce que tu veux récupérer ? qu'y a t'il dans la base de données ?

itokia a dit…

Donc j'envoie bien idSecteur=1 avec Ajax.

J'ai deux listes : une secteur (secteur1,secteur2...)
et dans la deuxième je devrais récupérer les maisons du secteur.

Donc dans ma base j'ai une table secteur avec idSecteur et nomSecteur.
Une deuxième avec : Maison avec idMaison nomMaison et idSecteur.

Mekteb a dit…

ne met pas &(.'AjaxDt')... mais &(.AjaxDt), en suite, dans ton code html il y a les résultats de ta requête ?

Il doit y avoir une erreur de syntaxe html ou quelque chose comme ça, si ça avait été la requête AJAX il t'aurais renvoyé une erreur à la place du resultat.

itokia a dit…

Je viens de faire le test avec &(.AjaxDt) et plus rien ne fonctionne coté Ajax.

Après analyse de mon code Html je ne vois aucune erreur de syntaxe.

Ca ne serait pas plutot du coté de mon controler?

Petite question, pourquoi tu retourne un tableau de tableau avec $list_ville[$v->getId()] = $v->getNomVille();

Mekteb a dit…

Ce n'est pas un tableau de tableau, mais ça facilite les choses pour les traitements que tu vas faire avec ton formulaire. Si l'identifiant de ta valeur et son ID en base de données, quand tu vas traiter ton formulaire, tu n'aura qu'a récupérer l'identifiant de la ligne que tu veux dans ta table. Ici c'est un tableau simple : $maliste[Id_ligne] = valeur_de_la_ligne; Fait des tests avec la fonction var_dump(); regarde ce que tu retourne ta requet SQL dans ton controleur avant de la transformer en JSON.

itokia a dit…

J'ai rajouté un var_dump($dt) qui est le tableau mais cela ne m'affiche rien.

itokia a dit…

J'ai trouvé d'où provener mon erreur. Elle se situé dans mon fichier de route. Par contre j'obtiens ceci en réponse pre class='xdebug-var-dump' dir='ltr'
array (size=1)
font color='#888a85' string {"1":"dt 1"}
et rien ne s'affiche dans mon select.

Mekteb a dit…

Cela est vraiment bizar, j'aimerais bien voir ton code, donne moi ton adresse email dans un commentaire que je ne publierais pas, comme ça ce sera plus simple.

itokia a dit…

Merci Mekteb pour ton aide.

Grace à toi, tu as résolu mon problème sur lequel je bloquais depuis 4 jours.

Encore bravo pour ton Tuto

cescu a dit…

Bonjour Mekteb,

j'ai utilisé ton tuto qui est tres bien expliqué et je t'en remercie ça m'a fait avancer. Par contre je n'arrive pas à faire fonctionner tout ça avec le type entity. Dans un programme j'ai deux listes de choix Liste1 et Liste2 Liste2 contient des informations issues d'une bdd qui sont chargées en fonction du choix fait dans Liste1 Si je valide mon formulaire alors que j'ai laissé Liste1 sans la changer et que je choisis ce que je veux dans Liste2 je n'ai aucun problème. Par contre si je change dans Liste1 et que j'ai ce que je dois avoir dans Liste2 à la validation du formulaire j'ai : Invalid data. As tu deja rencontré ce problème. On m'a dit qu'il faut utiliser les évènements de formulaire Merci

Unknown a dit…

Additif,
dans mon précédent message j'ai omis de préciser que je travaille sur Symfony2, le twig et Ajax.

Mekteb a dit…

Je réponds à vos questions dès que possible, je suis très occupé en ce moment. désolé ;)