Détection d’aucun résultat sur l’auto-complétion de l’interface utilisateur jQuery

Avant que vous me les signaliez, oui, j’ai passé en revue la demi-douzaine d’articles sur ce sujet, mais je suis toujours bloqué quant à la raison pour laquelle cela ne fonctionne pas.

Mon objective est de détecter le moment où la saisie semi-automatique donne 0 résultats. Voici le code:

$.ajax({ url:'sample_list.foo2', type: 'get', success: function(data, textStatus, XMLHttpRequest) { var suggestions=data.split(","); $("#entitySearch").autocomplete({ source: suggestions, minLength: 3, select: function(e, ui) { entityAdd(ui.item.value); }, open: function(e, ui) { console.log($(".ui-autocomplete li").size()); }, search: function(e,ui) { console.log("search returned: " + $(".ui-autocomplete li").size()); }, close: function(e,ui) { console.log("on close" + $(".ui-autocomplete li").size()); $("#entitySearch").val(""); } }); $("#entitySearch").autocomplete("result", function(event, data) { if (!data) { alert('nothing found!'); } }) } }); 

La recherche elle-même fonctionne bien, je peux obtenir des résultats sans problème. Si je comprends bien, je devrais pouvoir intercepter les résultats avec le gestionnaire de saisie semi-automatique (“résultat”). Dans ce cas, il ne se déclenche jamais du tout. (Même une alerte générique ou console.log qui ne fait pas référence au nombre de résultats ne se déclenche jamais). Le gestionnaire d’événements ouvert affiche le nombre correct de résultats (lorsqu’il y a des résultats), et les gestionnaires d’événements de recherche et de fermeture signalent une taille de résultat toujours en retard.

J’ai l’impression que je manque quelque chose d’évident et de flagrant ici mais je ne le vois tout simplement pas.

jQueryUI 1.9

jQueryUI 1.9 a béni le widget autocomplete avec l’événement de response , que nous pouvons exploiter pour détecter si aucun résultat n’a été renvoyé:

Déclenchée une fois la recherche terminée, avant que le menu ne s’affiche. Utile pour la manipulation locale des données de suggestion, où un rappel de l’option source personnalisée n’est pas requirejs. Cet événement est toujours déclenché lorsqu’une recherche est terminée, même si le menu ne s’affiche pas car il n’y a aucun résultat ou que la saisie semi-automatique est désactivée.

Dans cette optique, le piratage que nous avons dû faire dans jQueryUI 1.8 est remplacé par:

 $(function() { $("input").autocomplete({ source: /* */, response: function(event, ui) { // ui.content is the array that's about to be sent to the response callback. if (ui.content.length === 0) { $("#empty-message").text("No results found"); } else { $("#empty-message").empty(); } } }); });​ 

Exemple: http://jsfiddle.net/andrewwhitaker/x5q6Q/


jQueryUI 1.8

Je ne pouvais pas trouver un moyen simple de le faire avec l’API jQueryUI, cependant, vous pourriez remplacer la fonction autocomplete._response par la vôtre, puis appeler la fonction jQueryUI par défaut ( mise à jour pour étendre l’object prototype l’autocomplétion) :

 var __response = $.ui.autocomplete.prototype._response; $.ui.autocomplete.prototype._response = function(content) { __response.apply(this, [content]); this.element.sortinggger("autocompletesearchcomplete", [content]); }; 

Et puis, liez un gestionnaire d’événement à l’événement autocompletesearchcomplete (le contenu est le résultat de la recherche, un tableau):

 $("input").bind("autocompletesearchcomplete", function(event, contents) { $("#results").html(contents.length); }); 

Ce qui se passe ici est que vous enregistrez la fonction de response de autocomplete dans une variable ( __response ), puis en utilisant apply pour l’appeler à nouveau. Je ne peux pas imaginer de mauvais effets de cette méthode puisque vous appelez la méthode par défaut. Comme nous modifions le prototype de l’object, cela fonctionnera pour tous les widgets de saisie semi-automatique.

Voici un exemple de travail : http://jsfiddle.net/andrewwhitaker/VEhyV/

Mon exemple utilise un tableau local comme source de données, mais je ne pense pas que cela devrait être important.


Mise à jour: vous pouvez également intégrer la nouvelle fonctionnalité dans son propre widget, en étendant la fonctionnalité de saisie semi-automatique par défaut:

 $.widget("ui.customautocomplete", $.extend({}, $.ui.autocomplete.prototype, { _response: function(contents){ $.ui.autocomplete.prototype._response.apply(this, arguments); $(this.element).sortinggger("autocompletesearchcomplete", [contents]); } })); 

Changer votre appel de .autocomplete({...}); à:

 $("input").customautocomplete({..}); 

Et puis associez à l’événement autocompletesearchcomplete personnalisé plus tard:

 $("input").bind("autocompletesearchcomplete", function(event, contents) { $("#results").html(contents.length); }); 

Voir un exemple ici : http://jsfiddle.net/andrewwhitaker/VBTGJ/


Étant donné que cette question / réponse a attiré l’attention, j’ai pensé que je mettrais à jour cette réponse avec un autre moyen d’y parvenir. Cette méthode est particulièrement utile lorsque vous ne disposez que d’ un seul widget de saisie semi-automatique sur la page. Cette façon de procéder peut être appliquée à un widget de saisie semi-automatique qui utilise une source distante ou locale:

 var src = [...]; $("#auto").autocomplete({ source: function (request, response) { var results = $.ui.autocomplete.filter(src, request.term); if (!results.length) { $("#no-results").text("No results found!"); } else { $("#no-results").empty(); } response(results); } }); 

Dans le if est l’endroit où vous placeriez votre logique personnalisée à exécuter lorsque aucun résultat n’est détecté.

Exemple: http://jsfiddle.net/qz29K/

Si vous utilisez une source de données distante, dites quelque chose comme ceci:

 $("#auto").autocomplete({ source: "my_remote_src" }); 

Ensuite, vous devrez changer votre code pour que vous fassiez appel à AJAX et que vous détectiez 0 résultat:

 $("#auto").autocomplete({ source: function (request, response) { $.ajax({ url: "my_remote_src", data: request, success: function (data) { response(data); if (data.length === 0) { // Do logic for empty result. } }, error: function () { response([]); } }); } }); 

Si vous utilisez une source de données distante (comme une firebase database MySQL, PHP ou autre), il existe d’autres méthodes plus propres pour gérer une situation où il n’ya pas de données à retourner au client (sans besoin de hacks ou modifications de code d’interface utilisateur de code de base).

J’utilise PHP et MySQL comme source de données distante et JSON pour transmettre des informations entre eux. Dans mon cas, je semblais avoir des erreurs d’exception jQuery si la requête JSON n’avait pas reçu de réponse du serveur, alors j’ai trouvé plus simple de renvoyer une réponse JSON vide du côté serveur quand il n’y avait pas de données, puis de gérer le client. réponse de là:

 if (preg_match("/^[a-zA-Z0-9_]*$/", $_GET['callback'])) {//sanitize callback name $callback = $_GET['callback']; } else { die(); } die($callback . "([])"); 

Une autre méthode consisterait à renvoyer un indicateur dans la réponse du serveur pour indiquer qu’il n’y a pas de données correspondantes et effectuer des actions côté client en fonction de la présence (ou de la valeur) de l’indicateur dans la réponse. Dans ce cas, la réponse des serveurs serait quelque chose comme:

 die($callback . "([{'nodata':true}])"); 

Sur la base de cet indicateur, les actions peuvent être effectuées côté client:

 $.getJSON('response.php?callback=?', request, function (response) { if (typeof response[0].nodata !== 'undefined' && response[0].nodata === true) { alert('No data to display!'); } else { //Do whatever needs to be done in the event that there is actually data to display. } }); 

Tout le monde semble ignorer la manière simple et intégrée d’utiliser les messages: événement noResults.

 $('#field_name').autocomplete({ source: $('#field_name').data('autocomplete-source'), messages: { noResults: function(count) { console.log("There were no matches.") }, results: function(count) { console.log("There were " + count + " matches") } } }) 

Cette fonctionnalité a été ajoutée dans jQuery 1.9, en tant que fonctionnalité expérimentale ( décrite ici ). En juillet 2017, il n’était pas encore documenté dans l’API .

Après avoir initialisé votre élément autocomplete, définissez l’option de messages si vous souhaitez utiliser les scopes par défaut pour l’indication de message:

 $().autocomplete('option', 'messages', { noResults: 'myKewlMessage', results: function( amount ) { return amount + ( amount > 1 ? " results were" : " result was" ) + " found."; } }); 

NOTE : Ceci est une API expérimentale (non documentée). Les développeurs de l’interface utilisateur jQuery étudient toujours une solution complète pour la manipulation de chaînes et l’internationalisation.

Après des heures de jeu, j’ai finalement trouvé un truc pour afficher No match found in jQuery autocomplete. Regardez le code ci-dessus et ajoutez simplement un div , dans mon cas #ulNoMatch et son style défini pour se displap:none . Dans la méthode de succès de rappel, vérifiez si la length == 0 du tableau renvoyé est length == 0 . Si c’est la que vous allez, vous avez fait votre journée! 🙂

 
   Enter code here 

Je ne vois pas pourquoi source paramètre source avec un rappel personnalisé ne suffit pas . En supposant que nous utilisons un service JSON (P), gardez simplement à l’esprit les points suivants:

Le script côté serveur doit produire un JSON valide même si aucun résultat n’est trouvé – et [] est un JSON valide.

La documentation du paramètre source suggère que:

Un rappel de réponse, qui attend un seul argument: les données à suggérer à l’utilisateur. Ces données doivent être filtrées en fonction du terme fourni et peuvent être dans l’un des formats décrits ci-dessus pour les données locales simples. Il est important de fournir un rappel source personnalisé pour gérer les erreurs lors de la requête. Vous devez toujours appeler le rappel de réponse même si vous rencontrez une erreur . Cela garantit que le widget a toujours l’état correct.

En gardant ces deux points à l’esprit, les éléments suivants devraient suffire:

 $("#autocomplete").autocomplete({ source: function (request, response) { $.ajax({ url: "http://example.com/service.json", data: { q: this.term }, success: function (data, textStatus, jqXHR) { // data must be an array containing 0 or more items console.log("[SUCCESS] " + data.length + " item(s)"); response(data); }, error: function (jqXHR, textStatus, errorThrown) { // sortingggered when AJAX failed because of, for example, malformed JSON console.log("[ERROR] n/a item(s)"); response([]); } }); } }); 
 function SearchText() { $(".autosuggest").autocomplete({ source: function (request, response) { $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: "Default.aspx/GetAutoCompleteData", data: "{'username':'" + document.getElementById('txtSearch').value + "'}", dataType: "json", success: function (data.d) { if ((data.d).length == 0) { alert("no result found"); } response(data.d); }, error: function (result) { alert("Error"); } }); } }); } 
 The easiest straight forward way to do it. $("#search-box").autocomplete({ minLength: 2, source:function (request, response) { $.ajax({ url: urlPref + "/Api/SearchItems", data: { term: request.term }, success: function (data) { if (data.length == 0) { data.push({ Id: 0, Title: "No results found" }); } response(data); } }); },