web-dev-qa-db-fra.com

Détecter aucun résultat sur l'auto-complétion de l'interface utilisateur jQuery

Avant que vous me dirigiez vers eux, oui, j'ai examiné la demi-douzaine d'articles sur ce sujet, mais je ne comprends toujours pas pourquoi cela ne fonctionne pas.

Mon objectif est de détecter les cas où la saisie semi-automatique donne 0 résultat. 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 devrait être capable d'intercepter les résultats avec le gestionnaire autocomplete ("result"). Dans ce cas, il ne tire 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 indique le nombre correct de résultats (lorsqu'il y en a), et les gestionnaires d'événements de recherche et de fermeture indiquent une taille de résultat toujours en retard.

Je sens que je manque quelque chose d’évident et de flagrant ici mais je ne le vois tout simplement pas.

88
ScottyDont

jQueryUI 1.9

jQueryUI 1.9 a doté le widget autocomplete de l'événement response, que nous pouvons utiliser pour détecter si aucun résultat n'a été renvoyé:

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

Donc, dans cet esprit, le piratage informatique que nous devions 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 faire cela avec l'API jQueryUI. Cependant, vous pouvez remplacer la fonction autocomplete._response Par la vôtre, puis appeler la fonction par défaut jQueryUI ( mise à jour étendre l'objet prototype de l'auto-complétion) :

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

Et liez ensuite un gestionnaire d’événements à 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, c’est que vous enregistrez la fonction response d’auto-complétion dans une variable (__response), Puis vous utilisez apply pour l’appeler à nouveau. Je ne peux pas imaginer d'effets néfastes de cette méthode puisque vous appelez la méthode par défaut. Puisque nous modifions le prototype de l'objet, 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 en tant que source de données, mais je ne pense pas que cela devrait avoir de l'importance.


Mise à jour: Vous pouvez également envelopper 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).trigger("autocompletesearchcomplete", [contents]);
  }
}));

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

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

Et liez ensuite à l'événement personnalisé autocompletesearchcomplete ultérieurement:

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

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


Puisque cette question/réponse a attiré l'attention, j'ai pensé mettre à jour cette réponse avec encore un autre moyen d'accomplir cela. Cette méthode est particulièrement utile lorsque vous ne disposez que d'un seul widget 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);
    }
});

À l'intérieur de if, vous placerez votre logique personnalisée à exécuter lorsqu'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 le AJAX appelle vous-même et détecte quand 0 résultat est renvoyé:

$("#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([]);
            }
        });
    }
});
195
Andrew Whitaker

Tout le monde semble ignorer la manière simple et intégrée: utilisez l'événement messages: 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, à titre expérimental ( décrit ici ). En juillet 2017, il n'était pas encore documenté dans l'API .

5
Mike Bethany

Si vous utilisez une source de données distante (telle qu'une base de données MySQL, PHP , ou autre chose du côté serveur), il existe deux autres moyens plus propres de gérer une situation dans laquelle il n'y a pas de données à renvoyer au client (sans qu'il soit nécessaire de procéder à des hacks ou à des modifications du code de l'interface utilisateur du code principal).

J'utilise PHP et MySQL comme source de données distante et JSON pour transmettre des informations entre eux. J'ai donc trouvé plus facile de renvoyer une réponse JSON vide du côté du serveur lorsqu'il n'y a pas de données, puis de gérer la réponse du client à partir de là:

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

die($callback . "([])");

Une autre solution consisterait à renvoyer un indicateur dans la réponse du serveur pour indiquer qu’il n’existe aucune donnée correspondante et à effectuer des actions côté client en fonction de la présence (et/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}])");

Ensuite, en fonction de cet indicateur, des 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.
    }
});
2
Zappa

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

$(<yourselector>).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 jQuery UI étudient toujours une solution complète pour la manipulation et l'internationalisation des chaînes.

2
Guntram

Je ne vois pas pourquoi le paramètre source avec un rappel personnalisé est pas suffisant:

$("#autocomplete").autocomplete({
    source: function (request, response) {
        $.ajax({
            url: "http://example.com/service.json",
            data: {
                q: this.term
            },
            success: function (data, textStatus, jqXHR) {
                // data would be an array containing 0 or more items
                console.log("[SUCCESS] search returned " + data.length + " item(s)");
                response(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                // triggered when AJAX failed because of, for example, malformed JSON
                console.log("[FAILURE] search returned error");
                response([]);
            }
        });
    }
});
0
Salman A

Après des heures de jeu, j’ai enfin trouvé un moyen d’afficher No match found en saisie semi-automatique jQuery. Regardez le code ci-dessus et ajoutez simplement un div, dans mon cas #ulNoMatch et son style mis à displap:none. Dans la méthode de rappel de succès, vérifiez si le tableau renvoyé a length == 0. Si c'est là tu vas, tu as fait ta journée! :)

<pre><div class="ui-widget1" style="width: auto;">
    <asp:TextBox ID="txtSearch" class="tb" runat="server" Width="150px">
    </asp:TextBox>
    <ul id="ulNoMatch" class="ui-autocomplete ui-menu ui-widget1 ui-widget1-content ui-corner-all"
        role="listbox" aria-activedescendant="ui-active-menuitem" style="z-index: 16;
        display: none; width: 150px;">
        <li class="ui-menu-item" role="menuitem"><a class="ui-corner-all" tabindex="-1">No Matches
            Found</a></li>
    </ul>
    </div><pre>
<b>
<b>

Enter code here

<script>
    $(function () {
        $("input[id$='txtSearch']").autocomplete({
            source: function (request, response) {
                $.ajax({
                    url: "splah.aspx/GetByName",
                    data: "{ 'strName': '" + request.term.trim() + "' }",
                    dataType: "json",
                    type: "POST",
                    //cacheLength: 1,
                    contentType: "application/json; charset=utf-8",
                    dataFilter: function (data) {
                        return data; },
                    success: function (data) {
                        var found = $.map(data.d, function (item) {
                            return {
                                value: item.Name,
                                id: item.id
                            }
                         });

                         if (found.length == 0)
                         {
                             $("#ulNoMatch").show();
                         }
                         else
                         {
                             $("#ulNoMatch").hide();
                         }
                         response(found);
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        alert(textStatus);
                    }
                });
            },
            select: function (event, ui) {
                $("input[id$='txtSearch']").val(ui.item.label);
                $("input[id$='txtID']").val(ui.item.id);
                return false;
            },
            minLength: 1
        });
    });
</script>
0
Umar Malik