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

Я відчуваю, що пропускаю тут щось очевидне і кричуще, але я просто цього не бачу.


Схоже, це непростий спосіб зробити це за допомогою віджета автозаповнення, керованого даними на стороні клієнта. Використання віддаленого джерела для віджету - варіант?
Andrew Whitaker

Відповіді:


199

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, будь-яка ідея, як я можу отримати доступ до елементів у масиві "вміст" за допомогою jQuery ???
Бонги

1
@Bongs: Ви повинні мати доступ до нього безпосередньо за покажчикомcontents[0]
Ендрю Вітакер,

Насправді річ у тому, що масив вмісту був заповнений іменем користувача та його зображенням, і він не зміг отримати до нього доступ, вказавши значення індексу. Але вирішив рішення. Довелося згадати like, content [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 .__ відповідь
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. Подивіться на наведений вище код і просто додайте a 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

Я не розумію , чому 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");
         }
         });
        }
     });
  }

Ця відповідь не вносить нічого нового, прийнята відповідь має той самий код.
Мартін

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

Ця відповідь не вносить нічого нового, прийнята відповідь має той самий код.
Мартін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.