Home > Software engineering >  Symfony dynamic search field using Ajax
Symfony dynamic search field using Ajax

Time:04-19

I wanted to implement a dynamic search using Ajax in Symfony. I have an entity and a table in my database called Session. I want to load data from the table and display them in the template. Then, using a text field, I can simply write what I'm searching for and it would dynamically show up.

I can load from the database, and I can implement a search using a submit button that would refresh the page. But that's not what I want, I don't want to refresh I want it to be dynamic or what some would call a live search.

Here is my SessionController.php

    /**
 * @Route("/", name="app_session_index", methods={"GET", "POST"})
 * @param Request $request
 * @return Response
 */
public function index(Request $request): Response
{
    $propertySearch = new MyPropertySearch();
    //si si aucun nom n'est fourni on affiche tous les articles
    $sessions= $this->getDoctrine()->getRepository(Session::class)->findAll();
    $form = $this->createForm(PropertySearchType::class, $propertySearch);
    $form->handleRequest($request);
    //initialement le tableau des articles est vide,
    //c.a.d on affiche les articles que lorsque l'utilisateur clique sur le bouton rechercher
    $articles= [];

    if($form->isSubmitted() && $form->isValid()) {
        //on récupère le nom d'article tapé dans le formulaire
        $titre = $propertySearch->getTitle();
        if ($titre!="")
            //si on a fourni un nom d'article on affiche tous les articles ayant ce nom
            $sessions= $this->getDoctrine()->getRepository(Session::class)
                ->findByMultiple($titre);
    }
    return  $this->render('session/index.html.twig',[ 'form' =>$form->createView(), 'sessions' => $sessions]);
}

Here is it using an entity and it's Form called PropertySearchType.php which I've created. I don't believe it is relevant. It is however using the

findByMultuple($titre)

method which is a custom QueryBuilder method to search for a Session using multiple criterias.

    /**
//  * @return Session[] Returns an array of Session objects
//  */

public function findByMultiple($searchValue)
{
    return $this->createQueryBuilder('s')
        ->join('s.coach', 'c')
        ->addSelect('c')
        ->where('s.title LIKE :title')
        ->orWhere('s.description LIKE :desc')
        ->orWhere('s.rating LIKE :rate')
        ->orWhere('c.tier LIKE :tier')
        ->setParameters(
            ['title' => $searchValue, 'tier'=>$searchValue,
                'desc'=>$searchValue, 'rate'=>$searchValue
            ])
        ->getQuery()
        ->getResult();
}

And finally, it should be outputting what I need to the session/index.html.twig view containing the javascript and ajax necessary. It does render all the sessions when I refresh and a text field to write in. But as I write what I'm searching for, the table doesn't change.

Here is the twig file I'm rendering

    {% extends 'base.html.twig' %}
{% block title %}Session index{% endblock %}

{% block body %}
    <h1>Session index</h1>
    <h2>Search A Session !!</h2>

    <div >

        <div >

            <input type="text" id="search"  placeholder="Search here">
        </div>
    </div>
    <table >
        <thead>
            <tr>
                <th>Id</th>
                <th>Title</th>
                <th>Description</th>
                <th>Date</th>
                <th>StartTime</th>
                <th>Link</th>
                <th>Rating</th>
                <th>actions</th>
            </tr>
        </thead>
        <tbody>
        {% for session in sessions %}
            <tr>
                <td>{{ session.id }}</td>
                <td>{{ session.title }}</td>
                <td>{{ session.description }}</td>
                <td>{{ session.date ? session.date|date('Y-m-d') : '' }}</td>
                <td>{{ session.startTime ? session.startTime|date('H:i:s') : '' }}</td>
                <td>{{ session.link }}</td>
                <td>{{ session.rating }}</td>
                <td>
                    <a href="{{ path('app_session_show', {'id': session.id}) }}">show</a>
                    <a href="{{ path('app_session_edit', {'id': session.id}) }}">edit</a>
                </td>
            </tr>
        {% else %}
            <tr>
                <td colspan="8">no records found</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
     <a href="{{ path('app_session_new') }}">Create new</a>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js">
    </script>
    <script type="text/javascript">
        jQuery( document ).ready(function() {
            var searchRequest = null;
            $("#search").keyup(function(e){
                /* La variable value va prendre la valeur insérer dans le champ de texte afin d’effectuer la recherche */
                var value = $(this).val();
                /* Ajax est lancé lors du remplissage du champ texte dont l’id est « search » pour faire la recherche */
                $.ajax({
                    /* l’url est une chaine de caractères contenant l’adresse où la requête est envoyée */
                    url :{{ path('searchSessions') }},
                    /* La méthode utilisée pour transférer les données est GET */
                    type : 'GET',
                    /*Ici search value va prendre la chaine entrée par un utilisateur dans la zone de recherche et sera placée après l’url */
                    data: {
                        'searchValue' : value
                    },
                    /*Cette fonction permet de vider le contenu du tableau pour recevoir le nouveau contenu*/
                    success : function(retour){
                        if(retour){
                            $('#t tbody#search').empty();
                            $.each(JSON.parse(retour), function(i, obj) {
                                $('#t tbody#all').hide();
                                $('#t tbody#search').append('<tr><td> ' obj.id '  </td><td>    ' obj.title '  </td>'  
                                    '<td>' obj.description ' </td><td>' obj.date ' </td><td>    ' obj.startTime '  </td>'  
                                    '<td>    ' obj.link '  </td><td>    ' obj.rating '  </td>'  
                                    '<td><a href="/' obj.id '/edit">edit</a> </br>'  
                                    '<a href="/' obj.id '">remove</a></td></tr>');
    
                            });
                        }
                        else
                        {
                            $('#t tbody#all').show();
                            $('#t tbody#search').empty();
                            $('#t tbody#search').fadeIn('fast');
                        }``
                    },
                });
                return false;
            });
        });
    </script>
    {% endblock %}

Visual representation!!

CodePudding user response:

First thing I notice is in your twig code : you call {{ path('searchSessions') }} but the route define in your symfony code is app_session_index.

Try your symfony route with Postman (or another alike software) and if it works correctly then continue with you javascript code.

Else you won't be able to find out the source of the problem (or it will take more time :))

CodePudding user response:

Try to isolate your use case, you won't be able to debug if you don't know what code is executed.

As I said earlier use Postman to test you back-end code, then when I work as you want add the AJAX calls.

public function index(Request $request): Response
{
    $propertySearch = new MyPropertySearch();
    $form = $this->createForm(PropertySearchType::class, $propertySearch);
    $form->handleRequest($request);
    if($form->isSubmitted() && $form->isValid()) {
        // TEST IF YOU ARE PASSING HERE
        //on récupère le nom d'article tapé dans le formulaire
        $titre = $propertySearch->getTitle();
        // TEST IF TITLE IS CORRECT
        if ($titre!="") {
            // TEST IF findByMultiple WORK AS YOU WANT
            //si on a fourni un nom d'article on affiche tous les articles ayant ce nom
            $sessions= $this->getDoctrine()->getRepository(Session::class)
            ->findByMultiple($titre);
        }
    } else {
        // TEST IF YOU ARE PASSING HERE
        //si si aucun nom n'est fourni on affiche tous les articles
        $sessions= $this->getDoctrine()->getRepository(Session::class)->findAll();
    }
    return  $this->render('session/index.html.twig',[ 'form' =>$form->createView(), 'sessions' => $sessions]);
}
  • Related