Обнаружение отсутствия результатов при автозаполнении jQuery UI - PullRequest
88 голосов
/ 18 января 2011

Перед тем, как вы укажете мне на них, да, я просмотрел полдюжины сообщений на эту тему, но я все еще не понимаю, почему это не работает.

Моя цель - определить, когда автозаполнение дает 0 результатов. Вот код:

 $.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!'); }

  })
 }
}); 

Сам поиск работает нормально, я могу получить результаты без проблем. Насколько я понимаю, я должен иметь возможность перехватывать результаты с помощью обработчика автозаполнения ("результата"). В этом случае он никогда не срабатывает. (Даже общее предупреждение или console.log, которое не ссылается на количество результатов, никогда не срабатывает). Обработчик события open показывает правильное количество результатов (если они есть), а обработчики событий поиска и закрытия сообщают о размере результата, который всегда на один шаг позади.

Я чувствую, что упускаю что-то очевидное и ослепительно, но я просто не вижу этого.

Ответы [ 8 ]

195 голосов
/ 18 января 2011

jQueryUI 1.9

jQueryUI 1.9 благословил виджет автозаполнения с событием response, которое мы можем использовать, чтобы обнаружить, если результаты не возвращены:

Сработал после поисказавершается, прежде чем появится меню.Полезно для локальных манипуляций с данными предложений, когда обратный вызов пользовательской опции источника не требуется.Это событие всегда инициируется, когда поиск завершается, даже если меню не будет отображаться из-за отсутствия результатов или автозаполнение отключено.

Итак, с учетом этого, взлома нам пришлосьdo в jQueryUI 1.8 заменяется на:

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

Пример: http://jsfiddle.net/andrewwhitaker/x5q6Q/

jQueryUI 1.8

Я не смог найти простой способ сделать это с помощью jQueryUI API, однако вы могли бы заменить функцию autocomplete._response своей собственной, а затем вызвать функцию jQueryUI по умолчанию ( обновлено для расширения объекта prototype автозаполнения) :

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

и затем привязать обработчик события к событию autocompletesearchcomplete (содержимое - результат поиска, массив):

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

Здесь происходит то, что вы сохраняете функцию response автозаполнения в переменную (__response) и затем используете apply для ее повторного вызова.Я не могу представить никаких побочных эффектов от этого метода, так как вы вызываете метод по умолчанию.Поскольку мы модифицируем прототип объекта, это будет работать для всех виджетов автозаполнения.

Вот рабочий пример : http://jsfiddle.net/andrewwhitaker/VEhyV/

В моем примере используется локальный массив какисточник данных, но я не думаю, что это должно иметь значение.

Обновление: Вы также можете обернуть новую функциональность в свой собственный виджет, расширив функцию автозаполнения по умолчанию:

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

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

Изменение вашего звонка с .autocomplete({...}); на:

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

А затем привязать к пользовательскому событию autocompletesearchcomplete позже:

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

См. Пример здесь : http://jsfiddle.net/andrewwhitaker/VBTGJ/

Поскольку этот вопрос / ответ привлек некоторое внимание, я подумал, что обновлю этот ответ еще одним способом сделать это.Этот метод наиболее полезен, когда у вас есть только один виджет автозаполнения на странице.Этот способ может быть применен к виджету автозаполнения, который использует удаленный или локальный источник:

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

Внутри if находится место, где вы бы поместили свою пользовательскую логику для выполнения, когда результаты не обнаружены.

Пример: http://jsfiddle.net/qz29K/

Если вы используете удаленный источник данных, произнесите что-то вроде этого:

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

Тогда вынеобходимо изменить код так, чтобы вы сами вызывали AJAX и могли определить, когда возвращается 0 результатов:

$("#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([]);
            }
        });
    }
});
5 голосов
/ 15 июля 2015

Кажется, что все игнорируют простой, встроенный способ: используйте событие 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")
    }
  }
})

Эта функция была добавлена ​​в jQuery 1.9 в качестве экспериментальной функции ( описана здесь).По состоянию на июль 2017 года он еще не документирован в API .

2 голосов
/ 27 мая 2014

После инициализации элемента автозаполнения установите опцию сообщений, если вы хотите использовать диапазоны по умолчанию для индикации сообщений:

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

ПРИМЕЧАНИЕ : это экспериментальный API (не документирован),Разработчики jQuery UI все еще изучают полное решение для работы со строками и интернационализации.

2 голосов
/ 31 января 2012

Если вы используете удаленный источник данных (например, базу данных MySQL, PHP или что-то еще на стороне сервера), есть пара других более чистых способов справиться с ситуацией, когда нет данных для возврата клиенту (без необходимости каких-либо хаков или изменений кода пользовательского кода ядра).

Я использую PHP и MySQL в качестве удаленного источника данных и JSON для передачи информации между ними. В моем случае мне показалось, что я получаю ошибки исключения jQuery, если запрос JSON не получает какой-либо ответ от сервера, поэтому мне было проще просто вернуть пустой ответ JSON со стороны сервера, когда данных нет, а затем обработать клиент Ответ оттуда:

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

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

Другим способом было бы вернуть флаг в ответе от сервера, чтобы указать, что нет соответствующих данных, и выполнить действия на стороне клиента на основании наличия (и / или значения) флага в ответе. В этом случае ответ сервера будет выглядеть примерно так:

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

Тогда на основании этого флага могут быть выполнены действия на стороне клиента:

$.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.
    }
});
0 голосов
/ 09 января 2014
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);
                            }
                            });
                        },
0 голосов
/ 02 декабря 2013

Я не понимаю, почему source параметр с пользовательским обратным вызовом не достаточно:

$("#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 голосов
/ 27 сентября 2013
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");
         }
         });
        }
     });
  }
0 голосов
/ 29 мая 2012

После нескольких часов игры я наконец нашел способ показать No match found в автозаполнении jQuery.Посмотрите на приведенный выше код и просто добавьте div, в моем случае #ulNoMatch и его стиль установлен на displap:none.В методе успеха обратного вызова проверьте, имеет ли возвращенный массив length == 0.Если это там, вы идете, вы сделали свой день!:)

<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>
...