Partage
  • Partager sur Facebook
  • Partager sur Twitter

Symfony4 et AJAX

    22 mars 2019 à 11:23:54

    Bonjour à tous, je vous explique mon point de blocage :

    J'effectue une requête Ajax, qui ensuite est traitée par un querybuilder dans mon Repository puis retourné sous forme de Response() afin de l'afficher dans ma vue.

    Jusqu'ici cela fonctionne bien, je le fait ainsi (je synthétise le code) :

                $.ajax({
                    url: path,
                    type: "POST",
                    data: {
                        "data": param
                    },
                    dataType: "json",
                    async: true,
                    success: function (data) {
                        for (var i = 0; i < data.length; i++) {
                            $('#testAffichage').append(data[i].UserEmail);
                        }
                    }
                });
        /**
         * @Route("/multisearch", name="multisearch")
         */
        public function multiSearch(Request $request)
        {
            $criterias = $request->request->get('data');
    
            $jointureRepository = $this->getDoctrine()->getRepository(Jointure::class);
            $jointure = $jointureRepository->findByCriterias($criterias);
            
            $resultJson = json_encode($jointure);
            $jointure = new Response($resultJson);
            $jointure->headers->set('Content-Type', 'application/json');
            return $jointure;
    
        }

    Ceci fonctionne bien, mon tableau d'objet data[] est bien affiché au clique sur ma 

    <div id="testAffichage"></div>

    Mais je souhaite envoyé ce tableau dans un template Twig comme ceci afin de faire des traitements dessus et un affichage amélioré :

            $resultJson = json_encode($jointure);
            $jointure = new Response($resultJson);
            $jointure->headers->set('Content-Type', 'application/json');
      
            return $this->render('pages/searchresults.html.twig', [
                'jointure' => $jointure,
            ]);

    Mon template twig 'searchresults.html.twig' :

    {% if jointure is defined %}
    {% for jointures in jointure %}
    {{ jointures.UserEmail }}
    {% endfor %}
    {% endif %}

    Dans ce cas de figure , rien ne se passe, je n'ai même plus mon tableau dans l'onglet Reponse du DevDebugTool :(

    Merci d'avance à tous !

    -
    Edité par simsimz 22 mars 2019 à 11:47:10

    • Partager sur Facebook
    • Partager sur Twitter
      22 mars 2019 à 11:37:19

      Salut !

      Je ne comprends pas trop. D'une part tu encodes tes résultats en JSON, donc les convertis en une chaîne de caractères, et d'autre part, tu tentes de boucler dessus dans ton template… Ton adaptation pour l'affichage n'a pas été faite jusqu'au bout, là.

      Sinon, en ce qui me concerne, je ferais plutôt en sorte que ton JSON retourné précédemment contienne toutes les informations nécessaires pour que l'affichage amélioré soit géré en JavaScript. Vu que c'est le but principal, c'est dommage d'avoir simplifié aussi le code de la vue…

      • Partager sur Facebook
      • Partager sur Twitter
        22 mars 2019 à 11:49:32

        Merci pour ta réponse rapide comme à ton habitude @Ymox.

        Donc tu me conseil d'oublier ma gestion d'affichage en Twig mais de le faire en JS ?

        Ma fonction success en Ajax s'attend à un objet de type Réponse , donc je suis obligé de faire un encodage en JSON n'est-ce pas ?

        Je me suis insipiré de ce post : https://openclassrooms.com/forum/sujet/symfony2-communication-ajax-twig

        Il arrive à faire ce que je souhaite..

        Aurais-tu un exemple de code pour l'affichage en JS stp ?

        -
        Edité par simsimz 22 mars 2019 à 11:54:11

        • Partager sur Facebook
        • Partager sur Twitter
          22 mars 2019 à 11:52:03

          Je te conseille déjà ne plus sérialiser le retour de ta méthode en JSON pour le passer dans ta vue Twig et vouloir boucler dessus… Tu boucles souvent sur une chaîne de caractères ?

          Après, ne sachant pas exactement ce que tu souhaites faire comme « affichage amélioré », ça va être difficile de savoir comment t'aider.

          • Partager sur Facebook
          • Partager sur Twitter
            22 mars 2019 à 12:22:20

            Je viens de simplifier mon Controller de la sorte :

                /**
                 * @Route("/multisearch", name="multisearch")
                 */
                public function multiSearch(Request $request): JsonResponse
                {
                    $criterias = $request->request->get('data');
                    
                    // Find results
                    $jointureResults = $this->jointureRepository->findByCriterias($criterias);
            
                    // Symfony can return directly a Json encoded response like that :
                    return new JsonResponse($jointureResults, JsonResponse::HTTP_OK);
                }
            

            Pour l'instant je souhaite juste afficher la propriété UserEmail de mon tableau $jointureResults :) 

            Côté ajax je fais : 

                            success: function (data) {
                                for (var i = 0; i < data.length; i++) {
                                    $('.card').append(data[i].UserEmail);
                                }
                            }

            Côté html : 

                        <div class="container test">
                        <h3>Résultats :</h3>
                            <div id="searchResult"></div>
                            <div class="card card-body">
                            </div>
                        </div>

            En l'occurence , de cette façon, tous mes UserEmail récupéré vont dans le même <div class="card card-body">

            Je souhaite avoir un <div class="card card-body"> pour chaque UserEmail..

            J'imagine devoir faire document.getElementById(searchResult);

            et var newDiv = document.createElement("div");

            et lui ajouter la classe voulue : element.classList.add("card card-body");

            Tout ça dans le foreach ? 

            -
            Edité par simsimz 22 mars 2019 à 13:04:44

            • Partager sur Facebook
            • Partager sur Twitter
              22 mars 2019 à 13:15:44

              S'il n'y a que l'adresse mail à mettre dans ton div.card.card-body, ou/et que tu n'as pas une structure plus complexe à l'intérieur, je pense que je gérerais cette génération en JavaScript chez le client depuis la liste des adresses mail récupérées avec le JSON.
              Je note que tu utilises jQuery, ce qui te simplifierait la création de ton div en $('<div class="card card-body">' + mail + '</div>').

              Après, libre à toi de rendre les cartes et de retourner le HTML prêt à être inséré, ça peut être plus pratique surtout si la structure des cartes n'est pas juste un div avec deux classes et contenant une adresse mail.

              -
              Edité par Ymox 22 mars 2019 à 13:22:33

              • Partager sur Facebook
              • Partager sur Twitter
                22 mars 2019 à 15:14:31

                Merci pour l'astuce @Ymox, ça fonctionne bien :)

                  for (var i = 0; i < data.length; i++) {
                      $('#searchResult').append('<div class="card card-body">' + data[i].UserEmail + '</div>');
                  }

                Une dernière chose, lorsque je lance une nouvelle recherche, les résultats de la recherche précédente sont toujours affichés..


                • Partager sur Facebook
                • Partager sur Twitter
                  22 mars 2019 à 15:21:51

                  Evidemment, il faut vider le conteneur #searchResult avant de faire la boucle qui va ajouter les nouveaux résultats. Cela se fait avec la méthode jQuery .empty().

                  • Partager sur Facebook
                  • Partager sur Twitter
                    22 mars 2019 à 20:41:37

                    Bonjour,

                    Perso je renvoie toujours mes réponses ainsi:

                    Return new JsonRespones([
                    '_template' => $this->renderView('ta_vue)
                    ], JsonResponse::HTTP_OK);

                    Ensuite dans ta requête ajax tu fais response.template. 

                    DSL je suis avec mon tel donc c'est pas très pratique. 

                    En espérant t'avoir un peu aidé.

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Celui qui aime à apprendre est bien près du savoir " Confucius

                      23 mars 2019 à 11:29:18

                      Merci pour vos réponses Ymox et stoads :)

                      Pour l'instant j'ai un code fonctionnel en faisant ainsi, sans passer par Twig :

                      .append() Ajoute ton code à un code existant.

                      .html() le remplace.

                      Dans ma fonction $ajax() :

                                      success: function (data) {
                                          var content = '';
                                          for (var i = 0; i < data.length; i++) {
                                              content += '<div class="card card-body">' + data[i].UserEmail + '</div>';
                                          }
                                          $('#searchResult').html(content);
                                      }

                      @stoads, je conserve ta technique que j'aurai l'occasion d'utiliser plus tard ;)

                      Petite question annexe , jusqu'ici je met mon code JS/Jquery <script></script> en bas de mes templates Twig, je ne pense pas que cela soit une bonne pratique et je souhaite externaliser mes scripts JS. Connaissez-vous les bonnes pratiques Symfony4 sur ce sujet ? Merci d'avance.

                      -
                      Edité par simsimz 23 mars 2019 à 11:31:52

                      • Partager sur Facebook
                      • Partager sur Twitter
                        23 mars 2019 à 13:16:04

                        Salut,

                        Selon ta version de symfony asset ou webpack encore.

                        Si tu débutes je te conseil asset et ensuite quand tu auras un peu de temps webpack, le portage est très simple.

                        Avec asset c'est très simple et la doc symfony est très bien!

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Celui qui aime à apprendre est bien près du savoir " Confucius

                          27 mars 2019 à 10:09:24

                          D'accord je vais faire avec asset pour l'instant :)

                          Petite question annexe : J'ai une Entité "Category" qui est lié à une Entité "Compétences" en OneToMany.

                          Je souhaite avec deux boutons dropdown(liste déroulante) qui, pour "Category" affiche la liste de toutes les categories en BDD.

                          Lorsque je sélectionne une "Catégorie", je souhaite avoir au clique sur le bouton dropdown "Compétences" unqiuement le choix possible des Compétences qui sont liés à une Catégorie pré-sélectionné.

                          Avez-vous une idée de comment faire cela ? en JS ou AJAX évidemment :)

                          • Partager sur Facebook
                          • Partager sur Twitter
                            30 mars 2019 à 11:04:15

                            Bonjour,

                            Plusieurs solutions s'offrent à toi.

                            • Javascript: appel ajax puis tu remplaces tes balises <li>
                            • Utiliser les events des formulaires qui récupère ta donnée Catégorie sélectionnée puis grâce à un queryBuilder sur Compétence te renvoie les Compétences liées à la Catégorie sélectionnée

                            Deux liens intéressents:

                            https://symfony.com/doc/current/form/events.html

                            https://symfony.com/doc/current/form/dynamic_form_modification.html

                            PS: Choisir la doc en fonction de ta version de SF

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Celui qui aime à apprendre est bien près du savoir " Confucius

                              1 avril 2019 à 11:37:50

                              Merci stoads pour tes réponses, j'ai fait une requête ajax qui lance une querybuilder en fonction de l'id séléctionné , j'ignore pourquoi mais ma serialization de l'objet prend 20secondes minimum.. 

                              Peux-tu me montrer un exemple de comment tu renvois la "reponse.template" côté ajax comme tu m'a stipulé plus haut ?

                              Je n'arrive pas à polluer mon template Twig de cette façon.. si tu as un exemple de code c'est parfait :)

                              PS: mon éditeur de code sur le forum OC ne fonctionne plus.. error JS..

                              -
                              Edité par simsimz 1 avril 2019 à 11:38:15

                              • Partager sur Facebook
                              • Partager sur Twitter
                                1 avril 2019 à 19:50:43

                                Bonsoir,

                                <code>return new JsonResponse(['_template' => $this->renderView('le_nom_de_ta_vue.html.twig', ['param' => $param])], JsonResponse::HTTP_OK);</code>

                                Je te laisse regarder la différence entre render et renderView car c'est là toute la subtilité ;-)

                                Côté JS c'est du json response standard donc :

                                <code>

                                success: function(data) {

                                let template = data['_template'];

                                let searchContent = $('.search-content');

                                searchContent.html(template);

                                }

                                </code>

                                Que la sérialisation prenne du temps cela n'est pas normal. Essaie de limiter ta sérialisation pour voir.

                                A plus

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Celui qui aime à apprendre est bien près du savoir " Confucius

                                  2 avril 2019 à 15:31:49

                                  Encore merci Stoads, j'ai pu faire ce que je voulais grâce au renderView().

                                  Pour la serialization, j'ai créer une politique d'exclusion et n'ai plus de soucis de performance :)

                                  J'ai une dernière question , j'ai implémenter un bouton de recherche via un input, l'utilisateur renseigne un texte et mon controller renvoie les User qui correspondent ( soit au firstname du User , soit au mail du User).

                                  Mais je souhaite récupérer l'objet entier avec toutes les propriétés, pas uniquement le firstname ou le mail..

                                  Voici ma querybuilder ($value correspond à l'input text envoyer par l'utilisateur ) :

                                  public function findByEmail($value)
                                  {
                                  return $this->createQueryBuilder('u')
                                  ->select("u.firstname")
                                  ->select("u.mail")
                                  ->andWhere('u.mail LIKE :mail')
                                  ->orWhere('u.firstname LIKE :firstname')
                                  ->setParameter('firstname', '%'.$value.'%')
                                  ->setParameter('mail' , '%'.$value.'%')
                                  ->getQuery()
                                  ->getScalarResult()
                                  ;
                                  }
                                  Côté controller : 
                                  public function searchUser(Request $request)
                                  {
                                  $value = $request->request->get('inputsearch');

                                  $userResults = $this->userRepository->findByEmail($value);

                                  dump($userResults);die('userResults');
                                  return new JsonResponse([
                                  '_template' => $this->renderView('pages/result.html.twig', [
                                  'userResults' => $userResults]
                                  )],
                                  JsonResponse::HTTP_OK);
                                  }
                                  Mais ici le dump($userResults);me renvoie un array qui ne contient que le mail :

                                  array:2 [ 0 => array:1 [ "mail" => "sdelauney@peaks.fr" ] 1 => array:1 [ "mail" => "flaroque@peaks.fr" ] ]

                                  Comment faire pour que cette query me renvoie l'objet entier qui contient : "id" , "firstname" , "lastname" , "mail"..
                                  Encore merci.

                                  -
                                  Edité par simsimz 2 avril 2019 à 15:40:15

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    2 avril 2019 à 15:42:46

                                    Permettez que je fasse un petit test…

                                    public function findByEmail($value)
                                    {
                                        return $this->createQueryBuilder('u')
                                            ->select("u.firstname")
                                            ->select("u.mail")
                                            ->andWhere('u.mail LIKE :mail')
                                            ->orWhere('u.firstname LIKE :firstname')
                                            ->setParameter('firstname', '%' . $value . '%')
                                            ->setParameter('mail', '%' . $value . '%')
                                            ->getQuery()
                                            ->getScalarResult();
                                    }
                                    
                                    // Côté controller :
                                    public function searchUser(Request $request)
                                    {
                                        $value = $request->request->get('inputsearch');
                                    
                                        $userResults = $this->userRepository->findByEmail($value);
                                    
                                        dump($userResults);
                                        die('userResults');
                                        return new JsonResponse([
                                            '_template' => $this->renderView('pages/result.html.twig', [
                                                'userResults' => $userResults
                                            ])
                                        ], JsonResponse::HTTP_OK);
                                    }

                                    Edit

                                    Concluant, désactiver le JavaScript et rédiger en Markdown permet l'insertion de code dans une réponse.

                                    -
                                    Edité par Ymox 2 avril 2019 à 15:44:00

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      2 avril 2019 à 16:20:07

                                      Effectivement Ymox, c'est un bug general au site ou uniquement sur ma machine ?

                                      Je me permet de rajouter que la $value vient d'une fonction AJAX ( je souhaite ne pas avoir de refresh de page ) :

                                      function searchEmail(path) {
                                      var inputSearch = document.getElementById('input-search').value;
                                      $.ajax({
                                      url: path,
                                      type: "GET",
                                      dataType: "json",
                                      data: {"inputsearch": inputSearch},
                                      async: true,
                                      success: function (data) {
                                      console.log(data);
                                      let template = data['_template'];
                                      let searchContent = $('#search-content');
                                      searchContent.html(template);
                                      },
                                      error: function(data) {
                                      console.log('searchEmail ajax Error');
                                      }
                                      });
                                      }
                                      Je souhaite (simplement) retourner l'objet trouvé avec toutes ses propriétés ( ou une partie ) mais pas uniquement le "mail" comme actuellement.

                                      -
                                      Edité par simsimz 2 avril 2019 à 16:37:20

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        2 avril 2019 à 20:04:16

                                        Bonjour,

                                        ravie de t'aider.

                                        D'abord je renommerai ta méthode findByUsernameOrEmail car c'est ce que tu fais.

                                        <code type="php">

                                        public function findByUsernameOrByEmail($value)

                                        {

                                            return $this->createQueryBuilder('u')

                                                // Ici tu dis au query builder sélectionne moi firstname puis tu lui dis sélectionne moi mail

                                               // Que fais le query builder ? Il te sélectionne mail car c'est la dernière donnée qu'il a reçu en demande

                                               // Si tu veux firstname et name tu dois select('u.firstname') puis addSelect('u.mail') ou select('u.firstname, u.mail')

                                              // Si tu veux retourner l'entity createQueryBuilder ('u') suffit. createQueryBuilder retourne l'entity sur laquelle il pointe donc ici User

                                                ->select("u.firstname")

                                                ->select("u.mail")

                                                ->andWhere('u.mail LIKE :mail')

                                                // Attention à la case! Que ce passe t-il si input vaut ZOZOR et que firstname vaut zozor?

                                                ->orWhere('u.firstname LIKE :firstname')

                                                ->setParameter('firstname', '%' . $value . '%')

                                                ->setParameter('mail', '%' . $value . '%')

                                                ->getQuery()

                                                // Si tu retournes l'entity User getResult car POO.

                                                ->getScalarResult();

                                        }

                                        </code>

                                        J'espère que tu as assez de commentaires pour avancer! 

                                        PS : Pour l'insertion de code <code type="php">// Ici ton code </code> @Ymox Corrige moi si je me trompe!

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Celui qui aime à apprendre est bien près du savoir " Confucius

                                          2 avril 2019 à 22:12:38

                                          Effectivement stoads, c'est bien le "addSelect" qu'il me manquait et non pas le "select" simple :)

                                          Un grand merci :)

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            3 avril 2019 à 8:27:13

                                            stoads a écrit:

                                            Pour l'insertion de code <code type="php"<// Ici ton code </code> @Ymox Corrige moi si je me trompe!

                                            Alors <code> est uniquement pour la rédaction en Markdown, et celle-ci n'est plus accessible qu'en désactivant le JavaScript afin de désactiver le WYSIWYW qui fiche le dawa plus que de raison actuellement.
                                            De plus, <code> est pour du code inline, pas pour un pavé qui demande plutôt <pre>.
                                            Dernier point : l'attribut type n'existe pas pour ces deux balises. La subtilité pour que la coloration syntaxique puisse fonctionner ici, c'est d'utiliser class, et plutôt que de mettre une simple valeur PHP, c'est brush: php; qu'il faut utiliser — attention, il me semble bien que le ; final est important.

                                            -
                                            Edité par Ymox 3 avril 2019 à 8:30:03

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              3 avril 2019 à 19:44:34

                                              @Ymox Merci pour ces précisions. Au plaisir de te lire encore et encore.
                                              • Partager sur Facebook
                                              • Partager sur Twitter

                                              Celui qui aime à apprendre est bien près du savoir " Confucius

                                              Symfony4 et AJAX

                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                              • Editeur
                                              • Markdown