Non viene rilevato alcun risultato durante il completamento automatico dell'interfaccia utente jQuery


89

Prima che me li indichi, sì, ho esaminato la mezza dozzina di post su questo argomento, ma sono ancora perplesso sul motivo per cui non funziona.

Il mio obiettivo è rilevare quando il completamento automatico produce 0 risultati. Ecco il codice:

 $.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 ricerca stessa funziona bene, posso far apparire i risultati senza problemi. A quanto ho capito, dovrei essere in grado di intercettare i risultati con il gestore di completamento automatico ("risultato"). In questo caso, non si attiva mai. (Anche un avviso generico o console.log che non fa riferimento al numero di risultati non viene mai attivato). Il gestore eventi aperto mostra il numero corretto di risultati (quando sono presenti risultati) e i gestori eventi di ricerca e chiusura segnalano una dimensione dei risultati sempre un passo indietro.

Mi sento come se mi mancasse qualcosa di ovvio e lampante qui, ma semplicemente non lo vedo.


Sembra che non ci sia un modo semplice per farlo con un widget di completamento automatico guidato da dati lato client. Usare una sorgente remota per il widget è un'opzione?
Andrew Whitaker

Risposte:


199

jQueryUI 1.9

jQueryUI 1.9 ha benedetto il widget di completamento automatico con l' responseevento, che possiamo sfruttare per rilevare se non sono stati restituiti risultati:

Attivato al termine di una ricerca, prima che venga visualizzato il menu. Utile per la manipolazione locale dei dati dei suggerimenti, in cui non è richiesta una richiamata dell'opzione di origine personalizzata. Questo evento viene sempre attivato al termine di una ricerca, anche se il menu non verrà mostrato perché non ci sono risultati o il completamento automatico è disabilitato.

Quindi, con questo in mente, l'hacking che dovevamo fare in jQueryUI 1.8 è stato sostituito con:

$(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();
            }
        }
    });
});​

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


jQueryUI 1.8

Non sono riuscito a trovare un modo semplice per farlo con l'API jQueryUI, tuttavia, potresti sostituire la autocomplete._responsefunzione con la tua e quindi chiamare la funzione jQueryUI predefinita ( aggiornata per estendere l' prototypeoggetto del completamento automatico ) :

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

E quindi associa un gestore di eventi autocompletesearchcompleteall'evento (il contenuto è il risultato della ricerca, un array):

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

Quello che sta succedendo qui è che stai salvando la responsefunzione di completamento automatico in una variabile ( __response) e quindi usando applyper richiamarla di nuovo. Non riesco a immaginare alcun effetto negativo da questo metodo poiché stai chiamando il metodo predefinito. Poiché stiamo modificando il prototipo dell'oggetto, questo funzionerà per tutti i widget a completamento automatico.

Ecco un esempio funzionante : http://jsfiddle.net/andrewwhitaker/VEhyV/

Il mio esempio utilizza un array locale come origine dati, ma non credo che dovrebbe avere importanza.


Aggiornamento: puoi anche racchiudere la nuova funzionalità nel proprio widget, estendendo la funzionalità di completamento automatico predefinita:

$.widget("ui.customautocomplete", $.extend({}, $.ui.autocomplete.prototype, {

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

Modificare la chiamata da .autocomplete({...});a:

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

Quindi associa autocompletesearchcompleteall'evento personalizzato in un secondo momento:

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

Guarda un esempio qui : http://jsfiddle.net/andrewwhitaker/VBTGJ/


Poiché questa domanda / risposta ha ricevuto una certa attenzione, ho pensato di aggiornare questa risposta con un altro modo per ottenere ciò. Questo metodo è molto utile quando si ha solo un widget di completamento automatico nella pagina. Questo modo di farlo può essere applicato a un widget di completamento automatico che utilizza un'origine remota o 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);
    }
});

All'interno di ifè dove inseriresti la tua logica personalizzata da eseguire quando non vengono rilevati risultati.

Esempio: http://jsfiddle.net/qz29K/

Se stai utilizzando un'origine dati remota, dì qualcosa del genere:

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

Quindi dovrai cambiare il tuo codice in modo da effettuare la chiamata AJAX da solo e poter rilevare quando vengono restituiti 0 risultati:

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

@ Andrew, qualche idea su come posso accedere agli elementi nell'array "content" usando jQuery ???
Bong

1
@Bongs: dovresti essere in grado di accedervi direttamente dall'indicecontents[0]
Andrew Whitaker

In realtà il problema è che l'array dei contenuti è stato popolato con il nome utente e la sua immagine e non è stato possibile accedervi specificando il valore dell'indice. Ma ho trovato la soluzione. Ho dovuto menzionare come, i contenuti [i] .user.username ... :) grazie per la risposta e la fantastica soluzione ...
Bong

La soluzione di cui sopra funziona benissimo anche per il completamento automatico PrimeFaces (2.2.x) che si basa sullo stesso plugin jQuery.
wrschneider

3
In JqueryUI 1.8.19, la funzione _response è stata rinominata in __response. ( goo.gl/zAl88 ). Quindi, $ .ui.autocomplete.prototype._response diventa $ .ui.autocomplete.prototype .__ response
crazyphoton

6

Tutti sembrano ignorare il modo semplice e integrato: usa l'evento 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")
    }
  }
})

Questa funzionalità è stata aggiunta in jQuery 1.9, come funzionalità sperimentale ( descritta qui ). A luglio 2017, non è ancora documentato nell'API .


2

Se utilizzi un'origine dati remota (come un database MySQL, PHP o qualsiasi altra cosa sul lato server) ci sono un paio di altri modi più puliti per gestire una situazione in cui non ci sono dati da restituire al client (senza la necessità di alcun hack o modifiche al codice dell'interfaccia utente del codice principale).

Uso PHP e MySQL come origine dati remota e JSON per passare le informazioni tra di loro. Nel mio caso mi sembrava di ricevere errori di eccezione jQuery se la richiesta JSON non riceveva una sorta di risposta dal server, quindi ho trovato più semplice restituire una risposta JSON vuota dal lato server quando non ci sono dati e quindi gestire il client risposta da lì:

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

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

Un altro modo sarebbe restituire un flag nella risposta dal server per indicare che non ci sono dati corrispondenti ed eseguire azioni lato client in base alla presenza (e / o valore) del flag nella risposta. In questo caso la risposta del server sarebbe qualcosa del tipo:

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

Quindi in base a questo flag è possibile eseguire azioni lato 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

Dopo aver inizializzato l'elemento di completamento automatico, imposta l'opzione dei messaggi se desideri utilizzare gli intervalli predefiniti per l'indicazione dei messaggi:

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

NOTA : questa è un'API sperimentale (non documentata). Gli sviluppatori dell'interfaccia utente jQuery stanno ancora studiando una soluzione completa per la manipolazione delle stringhe e l'internazionalizzazione.


0

Dopo ore di gioco ho finalmente trovato un trucco da visualizzare No match foundnel completamento automatico di jQuery. Guarda il codice sopra e aggiungi semplicemente un div, nel mio caso #ulNoMatche il suo stile impostato su displap:none. Nel metodo callback riuscito controllare se l'array restituito ha length == 0. Se è lì, hai reso la tua giornata! :)

<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

Non vedo perché il sourceparametro con una richiamata personalizzata non sia sufficiente:

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

-1
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");
         }
         });
        }
     });
  }

Questa risposta non fornisce nulla di nuovo, la risposta accettata ha lo stesso codice.
Martin

-1
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);
                            }
                            });
                        },

Questa risposta non fornisce nulla di nuovo, la risposta accettata ha lo stesso codice.
Martin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.