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

89

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

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

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

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

Ответы:

200

jQueryUI 1.9

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

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

Итак, имея это в виду, взлом, который мы должны были сделать в 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([]);
            }
        });
    }
});
Эндрю Уитакер
источник
@Andrew, любая идея, как я могу получить доступ к элементам в массиве "content" с помощью jQuery ???
Bongs
1
@Bongs: у вас должен быть доступ к нему напрямую по индексуcontents[0]
Эндрю Уитакер,
На самом деле дело в том, что массив содержимого был заполнен именем пользователя и его изображением и не смог получить к нему доступ, указав значение индекса. Но разгадал решение. Пришлось упомянуть like, contents [i] .user.username ... :) спасибо за ответ и отличное решение ...
Bongs
Вышеупомянутое решение также отлично подходит для автозаполнения PrimeFaces (2.2.x), которое основано на том же плагине jQuery.
wrschneider
3
В JqueryUI 1.8.19 функция _response была переименована в __response. ( goo.gl/zAl88 ). Итак, $ .ui.autocomplete.prototype._response становится $ .ui.autocomplete.prototype .__ response
crazyphoton
6

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

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

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

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

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

Гунтрам
источник
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>
Умар Малик
источник
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

Я не понимаю , почему 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([]);
            }
        });
    }
});
Салман А
источник
-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");
         }
         });
        }
     });
  }
Селвин Джон
источник
Этот ответ не вносит ничего нового, принятый ответ имеет тот же код.
Мартин