8768 sujets

Développement web côté serveur, CMS

Bonjour à tous,

Avec Symfony 5.4, j'ai besoin de réaliser un bouton "load more", qui permet via une requête Ajax de récupérer les X prochains enregistrements en Json.

Jusqu'ici, tout va bien, je galère surtout sur la vue, car j'aimerais pouvoir utiliser les variables et fonctions de Twig avec JavaScript, et je n'y arrive pas. Je m'explique...

Avant d'implémenter cette fonctionnalité, je ne travaillais qu'avec des objets PHP, donc je pouvais facilement utiliser les fonctions de Twig comme path(), asset()... j'utilisais par exemple aussi un Voter afin de déterminer si oui on non j'affiche un bouton d'édition/de suppression de l'enregistrement à l'utilisateur, comme ceci :
{% if is_granted('FIGURE_EDIT', figure) %}
    <a href="{{ path('app_figure_edit', {'id': figure.id, 'slug': figure.slug}) }}" class="btn btn-outline-primary btn-sm" title="Modifier cette figure">
        <i class="bi bi-pencil"></i>
    </a>
{% endif %}


Mais maintenant, je reçois des données en Json au lieu d'une collection d'objets :

{
    "id": 63,
    "name": "Aenean nec ornare",
    "createdAt": "2022-05-28T11:22:14+00:00",
    "status": "status.accepted",
    "slug": "aenean-nec-ornare",
    "userId": 10,
    "userIdentifier": "Admin",
    "firstFigureImage": "400-629205e619369.jpg",
    "categoryName": "intermédiaire",
    "categorySlug": "intermediaire"
  },


Du coup, j'ai pensé en premier lieu à boucler sur le Json en Javascript pour afficher les infos, par exemple comme ceci :


function appendData(data) {

            var container = document.getElementById('figures-grid');
            var HTML = ``;

            for (let i = 0; i < data.length; i++) {

                HTML += `
                <div class="col">
                    <div class="card h-100">
                        <a href="/figure/show/` + data[i].id + `-` + data[i].slug + `">
                            <img class="card-img-top" src="/uploads/images/` + data[i].firstFigureImage + `">
                        </a>

                        <div class="card-body">
                            <h5 class="card-title">
                                <a href="/figure/show/` + data[i].id + `-` + data[i].slug + `">
                                    ` + data[i].name + `
                                </a>
                            </h5>
                        </div>
                    </div>
                </div>
                `;
            }
            index++;
            container.innerHTML += HTML;
}


Cette technique fonctionne si je dois juste afficher des infos, à coup de data[ i ].maPropriété, mais dès lors qu'on a besoin du dynamisme de Twig/PHP, c'est impossible : on ne peut pas écrire du Twig au sein d'une variable JS, ça ne fonctionne pas, et en plus, c'est trop tard puisque le serveur a déjà interprété l'affichage.
En tout cas, je ne trouve pas cette technique très propre.

Il semblerait que la bonne méthode consiste à préparer l'affichage côté PHP plutôt, avec Twig, et que c'est cet affichage qu'on renvoie via Ajax pour l'affichage... Mais je ne parviens pas à comprendre comme faire avec du Json, je trouve ça très déroutant Smiley lol

Est-ce que vous avez des pistes, des réflexions pour me mettre sur la bonne voie ? Merci d'avance !
Modifié par Loraga (06 Jun 2022 - 09:48)
Hello,

Oui le plus pratique est que ta requete ajax renvoie directement le html à afficher au lieu du json.
Tu peux utiliser twig dans ton controlleur et utiliser renderView (exemple dans la doc ici : https://symfony.com/doc/5.4/templates.html#rendering-templates )
Ensuite dans ton js, tu récupères le contenu que tu peux afficher avec un innerHTML.
Modifié par Surfoo (07 Jun 2022 - 00:49)
Merci pour ton message Smiley smile

J'ai continué à expérimenter de mon côté et la solution adoptée est quasiment identique à la tienne.
Avant de poster, je ne savais pas qu'on pouvait stocker le résultat d'un template Twig au sein d'une variable avec getContent(). Du coup, j'ai créé un template twig partiel, dans lequel je boucle sur mes enregistrements.
Au sein du controller, l'astuce réside dans le fait de stocker le contenu de ce template, et de le renvoyer au format texte, comme ceci :

/**
     * @Route("/loadmore/{page<\d+>?1}", name="app_loadmore")
     */
    public function loadMore(FigureManager $figureManager, int $page = 1): Response
    {
        $figurePerPage = 12;
        $beginAt = ($page - 1) * $figurePerPage;

        $content = $this->render('_parts/figure_grid.part.twig', [
            'figures' => $figureManager->findByStatusOrderByDateLimit(Figure::STATUS_ACCEPTED, $figurePerPage, $beginAt)
        ])->getContent();

        return new Response($content, 200, array('Content-Type' => 'text/html'));
    }


Le JavaScript se simplifie alors beaucoup puisqu'il faut seulement récupérer cette réponse et l'afficher instantanément :

function appendData(data) {
            var container = document.getElementById('figures-grid');

            index++;
            container.innerHTML += data;
}


En fait, j'avais du mal à comprendre la logique derrière l'affichage d'une requête Ajax, c'est un peu déroutant mais c'est très pratique de savoir faire ce genre de requête !
J'étais resté bloqué sur le Json... alors qu'il n'y avait pas forcément besoin de renvoyer du Json ^^