Обнаружение отсутствия результатов при автозаполнении пользовательского интерфейса jQuery

81

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

Моя цель - обнаружить, когда автозаполнение дает 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, который не ссылается на количество результатов, никогда не срабатывает). Открытый обработчик событий показывает правильное количество результатов (когда есть результаты), а обработчики событий поиска и закрытия сообщают о размере результата, который всегда находится на одном шаге.

Я чувствую, что мне не хватает чего-то очевидного и вопиющего, но я просто этого не вижу.

  • 0
    Похоже, что нет простого способа сделать это с помощью автозаполнения виджета, управляемого данными на стороне клиента. Является ли использование удаленного источника для виджета опцией?
Теги:
jquery-ui-autocomplete

8 ответов

175
Лучший ответ

jQueryUI 1.9

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

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

Итак, имея в виду, взлом, который мы должны были сделать в jQueryUI 1.8, заменяется на:

$(function() {
    $("input").autocomplete({
        source: /* */,
        response: function(event, ui) {
            // ui.content is the array that 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 по умолчанию (обновленную для расширения объекта autocomplete 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([]);
            }
        });
    }
});
  • 3
    Я приветствую ваше впечатляющее JQuery-фу. Самое элегантное решение. Если бы я мог отдать более одного голоса, я бы с удовольствием отдал 100. Спасибо за код и объяснение этого кода.
  • 1
    @ Thumbkin: Нет проблем, я удивлен, что нет более простого способа сделать это. Рад, что помог, хотя было весело работать!
Показать ещё 19 комментариев
2

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

  • 1
    Не было варианта в 2011 году.
  • 2
    @ScottyDont Вы имеете в виду, что они не могут вернуться во времени? ;) Но если честно, есть более свежие ответы. Это хорошая вещь в интернете, но она вне времени, и теперь люди видят, что мой ответ - лучшее решение.
2

Если вы используете удаленный источник данных (например, базу данных 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.
    }
});
1

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

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

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

  • 0
    @Martin tnx за эту заметку. не думал об этом ...
0
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
    Этот ответ не вносит ничего нового, принятый ответ имеет такой же код.
0

Я не понимаю, почему параметр source с пользовательским обратным вызовом недостаточно. Предполагая, что мы используем службу JSON (P), просто помните следующее:

Серверная сторона script должна выдавать действительный JSON, даже если результаты не найдены - и [] действителен JSON.

Документация для параметра source предполагает, что:

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

Сохраняя вышеуказанные две точки, должно быть достаточно:

$("#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) {
                // triggered when AJAX failed because of, for example, malformed JSON
                console.log("[ERROR] n/a item(s)");
                response([]);
            }
        });
    }
});
0

После нескольких часов игры я наконец нашел трюк, чтобы отобразить 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>
-2
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
    Этот ответ не вносит ничего нового, принятый ответ имеет такой же код.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню