Une recherche avancé en ajax avec jquery
par Admins · 19 juillet 2014
Qui n’a pas rêvé de pouvoir avoir une liste de suggestion à la Google sur son site ? Ce tuto est la pour ça.
Si vous êtes débrouillard, vous pourrez l’adapter facilement pour voir si un pseudo est disponible par exemple.
Dans ce tuto vous pourrez faire une recherche dans une base de donnée en ajax de deux manières:
- On recherche une partie d’un mot, exemple: sim pourrait suggérer Simon
- Si un mot contient un certain nombre de lettres, exemple: si on recherche les lettres S, M et I, on pourra suggérer Simon.
- On pourrait rajouter d’autre fonction encore…
Pour cela, j’ai choisit d’utiliser l’événement keyup qui détecte l’ajout de texte dans un input. Je trouve ça bien mieux que blur qui attend la perte du focus.
Donc en gros ce code récupère le texte tapé dans l’input, regarde le type de recherche choisit et va faire une requête ajax puis afficher le résultat. Simple non ?
Pour pimenter le tout:
- L’input change de couleur: vert si la recherche à trouvé quelque chose et rouge la recherche à échoué
- Les parties des mot recherché sont mise en valeur.
Bien sur pour évité de surcharger le serveur pour rien, on lance la recherche avec un nombre de caractère minimum.
Ensuite qu’est ce qu’on fait quand on à trouvé un mot ? Au clique on peut l’ajouter dans l’input!!! Il faut donc pouvoir détecter ce clique et pouvoir fermer le fenêtre de suggestion quand l’input perd le focus.
Pour les effets j’utilise le magnifique plugin Velocity.js qui est ultrat cool. Je vous laisse voir.
Place au code commenté:
<form class="search" method="post" action="search.php" > <input type="radio" name="recherche_type" value="1"> Au moins une de ces lettres - <input type="radio" name="recherche_type" value="2" checked> Normal <input type="text" class="recherche" id="recherche" name="recherche" value="" placeholder="Recherche..." autocomplete="off" /><input type="submit" id="submit" class="submit"> <ul id="results"></ul> </form>
$(document).ready(function() { $(document).on('keyup', '#recherche', function() { // Quand on écrit dans l'input var results = $('#results'); results.empty(); // On vide la liste results.addClass('results'); // On ajoute la class au div if($(this).val().length > 2) // Si supérieur ou égal à 3 caractères { var recherche_type = $("input[name=recherche_type][type=radio]:checked").val(); // On récupère le type de recherche voulu $('#results').velocity('fadeIn', { duration: 300, stagger: 50, drag: true }).html('<li>Chargement...</li>'); // On afiche un message pour faire patienter $.ajax({ url: '../ajax/autocomplete_liste_nom.php', type: 'GET', data: {'recherche': $(this).val(), 'type': recherche_type}, // On envoie deux choses: ce qu'on recherche et le type de recherche timeout: 5000, // Après 5 seconde on arrête si c'est trop long dataType: 'json', // Le type de données qu'on va recevoir success: function(donnees) { var texte_donnees_liste = ''; // On initialise la variable if(donnees.reponse == 1) // Si on a trouvé quelque chose { $(donnees['suggestions']).each(function(key, value) { // On boucle sur les éléments trouvé: texte_donnees_liste += '<li><a href="#" class="element_recherche">'+value+'</a></li>'; // On ajoute l'élément dans la variable qui contient un lien avec la class element_recherche }); $('#recherche').css({'background-color': '#25BA5C', 'color': 'white'}); // On change la couleur de l'input } else if(donnees.reponse == 2) // Si on à rien trouvé { texte_donnees_liste += '<li>Aucun élément</li>'; // On ajoute l'élément dans la variable $('#recherche').css({'background-color': '#D61A1A', 'color': 'white'}); // On change la couleur de l'input } else { texte_donnees_liste += '<li>Une erreur c\'est produite</li>'; // On ajoute l'élément dans la variable } results.html(texte_donnees_liste); // On affiche le contenu dans le div results en une seul fois }, error: function(XMLHttpRequest,textStatus, errorThrown){ // Si il y a une erreur results.html('<li><b>Erreur:</b> '+errorThrown+'</li>'); }, }); return false; } else // Si le nombre de caractères est inférieur à 3 { $('#recherche').css({'background-color': '#FFFFFF', 'color': 'black'}); results.html('<li>Plus de 3 caractères minimum</li>'); } }); $(document).on('click', '.element_recherche', function() { // Quand on clique sur un lien des éléments de la recherche qui doit contenire la class element_recherche $('#recherche').val( $(this).text() ); // On ajoute la valeur dans l'input(texte du lien) $('#results li').velocity('fadeOut', { duration: 1000, stagger: 350, drag: true }); // On ferme la liste de suggestion }); $(document).on('blur', '#recherche', function() { // Quand l'input perd le focus on cache la liste de suggestion $('#results').velocity('fadeOut', { duration: 800, stagger: 150, drag: true }); // On ferme la liste de suggestion }); });
if(!empty($_GET['recherche'])) // Si on à bien reçus la recherche { $q = trim($_GET['recherche']); // On supprime les espaces avant et à la fin if(@$_GET['type'] == 1) // Le mot doit contenir les lettres recherché quelque soit l'ordre... Si on recherche les lettres S, M et I, on pourra trouvé Simon { $sql = "SELECT * FROM `liste_nom` WHERE"; // Début de la requête SQL for ($i = 0; $i <= (strlen($q)-1); $i++) // On boucle sur les lettres de la recherche { $sql .= " AND nom LIKE :nom_".$i." "; // On ajout à la variable le nom de la colonne avec la clé de l'array de la variable $array_prepare $array_prepare['nom_'.$i] = '%'.$q[$i].'%'; // Array qui va contenir les données à pour la requête SQL $array_lettres[] = $q[$i]; // Array qui contient toute les lettres recherchés } $sql = substr($sql, 4); // On commence au 4 caractères pour ne pas afficher le AND ou on va avoir une erreur $sql .= "Order By nom ASC LIMIT 0,15"; // On termine la requête SQL pour classer les données et limiter l'affichage // La requête SQL: $stmt = $bdd->prepare($sql); $stmt->execute($array_prepare); $stmt->setFetchMode(PDO::FETCH_ASSOC); $donnees = $stmt->fetchAll(); // Le résultat est dans la variable $donnees // krumo($donnees); if(!empty($donnees)) // Si on obtient un résultat { $array['reponse'] = 1; // On donne la réponse 1 foreach ($donnees as $key => $value) // On liste les éléments récupéré { $mot = $value['nom']; // On met le mot courant dans une varaible $chaine = ''; // On initialise la variable for ($i = 0; $i <= (strlen($mot)-1); $i++) // On boucle sur chaque lettre du mot { if (in_array($mot[$i], $array_lettres)) // Si la lettre esnt dans l'array des lettres recherché on la met en valeur { $chaine .= '<span style="color:blue;font-weight: bold;">'.$mot[$i].'</span>'; } else { $chaine .= $mot[$i]; } $array['suggestions'][$key] = $chaine; // On l'ajoute dans l'array qui va être envoyé } } } else { $array['reponse'] = 2; // Si la recherche à échoué $array[] = ''; } echo json_encode($array); // On encode en json et on l'affiche } else // Mode de recherche normal { $stmt = $bdd->prepare("SELECT * FROM `liste_nom` WHERE nom LIKE :nom Order By nom ASC LIMIT 0,15"); // $stmt = $bdd->query("SELECT * FROM `liste`"); $stmt->execute(array('nom' => '%'.$q.'%')); $stmt->setFetchMode(PDO::FETCH_ASSOC); $donnees = $stmt->fetchAll(); if(!empty($donnees)) { $array['reponse'] = 1; // On donne la réponse 1 foreach ($donnees as $key => $value) { $array['suggestions'][] = str_ireplace($q, '<span style="color:blue;font-weight: bold;">'.$q.'</span>', $value['nom']); // On remplace les lettres recherché et on l'ajoute dans l'array qui va être envoyé } } else { $array['reponse'] = 2; // Si la recherche à échoué $array[] = ''; } echo json_encode($array); // On encode en json et on l'affiche } } else { // Si on reçoit pas la recherche }
input { font-family: 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13px; color: #555860; color:black; } .search { position: relative; margin: 0 auto; width: 300px; } .search .submit { height: 26px; /*width: 100%;*/ border-top-color: #BABDCC; border-left-color: #FFFFFF; border-right-color: #BABDCC; border-bottom-color: #BABDCC; border-width: 1px; border-style: solid; /*padding: 0 12px 0 25px; background: white url("http://data.simonbhb.fr/images/recherche_16_16.png") 4px 4px no-repeat;*/ background-image: -moz-linear-gradient(top, #f1f1f1, #ffffff); background-image: -ms-linear-gradient(top, #f1f1f1, #ffffff); background-image: -o-linear-gradient(top, #f1f1f1, #ffffff); background-image: -webkit-gradient(linear, center top, center bottom, from(#f1f1f1), to(#ffffff)); background-image: -webkit-linear-gradient(top, #f1f1f1, #ffffff); background-image: linear-gradient(top, #f1f1f1, #ffffff); -webkit-border-top-right-radius: 13px; -webkit-border-bottom-right-radius: 13px; -moz-border-radius-topright: 13px; -moz-border-radius-bottomright: 13px; border-top-right-radius: 13px; border-bottom-right-radius: 13px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; -webkit-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; -moz-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; -ms-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; -o-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; } .search .recherche { height: 26px; /*width: 100%;*/ border-top-color: #BABDCC; border-left-color: #BABDCC; border-right-color: #FFFFFF; border-bottom-color: #BABDCC; padding: 0 12px 0 25px; background: white url("http://cssdeck.com/uploads/media/items/5/5JuDgOa.png") 8px 6px no-repeat; border-width: 1px; border-style: solid; border-color: #a8acbc #babdcc #c0c3d2; -webkit-border-top-left-radius: 13px; -webkit-border-bottom-left-radius: 13px; -moz-border-radius-topleft: 13px; -moz-border-radius-bottomleft: 13px; border-top-left-radius: 13px; border-bottom-left-radius: 13px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; -webkit-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; -moz-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; -ms-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; -o-box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; box-shadow: inset 0 1px #e5e7ed, 0 1px 0 #fcfcfc; } .search input:focus { outline: none; border-color: #66b1ee; -webkit-box-shadow: 0 0 2px rgba(85, 168, 236, 0.9); -moz-box-shadow: 0 0 2px rgba(85, 168, 236, 0.9); -ms-box-shadow: 0 0 2px rgba(85, 168, 236, 0.9); -o-box-shadow: 0 0 2px rgba(85, 168, 236, 0.9); box-shadow: 0 0 2px rgba(85, 168, 236, 0.9); } .search input:focus + .results { display: block } .search .results { /* display: none;*/ position: absolute; top: 55px; left: 0; right: 0; z-index: 10; padding: 0; margin: 0; border-width: 1px; border-style: solid; border-color: #cbcfe2 #c8cee7 #c4c7d7; border-radius: 3px; background-color: #fdfdfd; background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fdfdfd), color-stop(100%, #eceef4)); background-image: -webkit-linear-gradient(top, #fdfdfd, #eceef4); background-image: -moz-linear-gradient(top, #fdfdfd, #eceef4); background-image: -ms-linear-gradient(top, #fdfdfd, #eceef4); background-image: -o-linear-gradient(top, #fdfdfd, #eceef4); background-image: linear-gradient(top, #fdfdfd, #eceef4); -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); -ms-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .search .results li { display: block } .search .results li:first-child { margin-top: -1px } .search .results li:first-child:before, .search .results li:first-child:after { display: block; content: ''; width: 0; height: 0; position: absolute; left: 50%; margin-left: -5px; border: 5px outset transparent; } .search .results li:first-child:before { border-bottom: 5px solid #c4c7d7; top: -11px; } .search .results li:first-child:after { border-bottom: 5px solid #fdfdfd; top: -10px; } .search .results li:first-child:hover:before, .search .results li:first-child:hover:after { display: none } .search .results li:last-child { margin-bottom: -1px } .search .results a { display: block; text-decoration: none; position: relative; margin: 0 -1px; padding: 6px 40px 6px 10px; color: #808394; font-weight: 500; text-shadow: 0 1px #fff; border: 1px solid transparent; border-radius: 3px; color:black; } .search .results a span { font-weight: 200 } .search .results a:before { content: ''; width: 18px; height: 18px; position: absolute; top: 50%; right: 10px; margin-top: -9px; background: url("http://cssdeck.com/uploads/media/items/7/7BNkBjd.png") 0 0 no-repeat; } .search .results a:hover { text-decoration: none; color: #fff; text-shadow: 0 -1px rgba(0, 0, 0, 0.3); border-color: #2380dd #2179d5 #1a60aa; background-color: #338cdf; background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #59aaf4), color-stop(100%, #338cdf)); background-image: -webkit-linear-gradient(top, #59aaf4, #338cdf); background-image: -moz-linear-gradient(top, #59aaf4, #338cdf); background-image: -ms-linear-gradient(top, #59aaf4, #338cdf); background-image: -o-linear-gradient(top, #59aaf4, #338cdf); background-image: linear-gradient(top, #59aaf4, #338cdf); -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), 0 1px rgba(0, 0, 0, 0.08); -moz-box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), 0 1px rgba(0, 0, 0, 0.08); -ms-box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), 0 1px rgba(0, 0, 0, 0.08); -o-box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), 0 1px rgba(0, 0, 0, 0.08); box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), 0 1px rgba(0, 0, 0, 0.08); }
PS: N’oubliez pas d’inclure jquery
Tous les codes sont testés et sont fonctionnels, si il arrive qu'un de ces codes ne fonctionne pas chez vous, merci de me le signaler.