Không phát hiện kết quả nào trên tự động hoàn thành giao diện người dùng jQuery


89

Trước khi bạn chỉ tôi với họ, vâng, tôi đã xem lại nửa tá bài đăng về chủ đề này, nhưng tôi vẫn băn khoăn là tại sao điều này không hoạt động.

Mục tiêu của tôi là phát hiện thời điểm tự động hoàn thành mang lại 0 kết quả. Đây là mã:

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

  })
 }
}); 

Bản thân việc tìm kiếm hoạt động tốt, tôi có thể hiển thị kết quả mà không có vấn đề gì. Theo tôi được biết, tôi nên có khả năng đánh chặn các kết quả với autocomplete ( "kết quả") xử lý. Trong trường hợp này, nó không bao giờ bắn cả. (Ngay cả một cảnh báo hoặc console.log chung chung không tham chiếu đến số lượng kết quả cũng không bao giờ kích hoạt). Trình xử lý sự kiện mở hiển thị số lượng kết quả chính xác (khi có kết quả) và trình xử lý sự kiện tìm kiếm và đóng báo cáo kích thước kết quả luôn chậm hơn một bước.

Tôi cảm thấy như tôi đang thiếu một cái gì đó rõ ràng và nhìn chằm chằm vào đây nhưng tôi không nhìn thấy nó.


Có vẻ như không có cách nào dễ dàng để thực hiện điều này với tiện ích con tự động hoàn thành được điều khiển bởi dữ liệu phía máy khách. Sử dụng nguồn từ xa cho tiện ích có phải là một tùy chọn không?
Andrew Whitaker

Câu trả lời:


199

jQueryUI 1.9

jQueryUI 1.9 đã ban phước cho tiện ích tự động hoàn thành với responsesự kiện, mà chúng tôi có thể tận dụng để phát hiện nếu không có kết quả nào được trả về:

Được kích hoạt sau khi tìm kiếm hoàn tất, trước khi menu được hiển thị. Hữu ích cho thao tác cục bộ dữ liệu đề xuất, nơi không cần gọi lại tùy chọn nguồn tùy chỉnh. Sự kiện này luôn được kích hoạt khi tìm kiếm hoàn tất, ngay cả khi menu sẽ không được hiển thị vì không có kết quả hoặc tính năng Tự động hoàn thành bị tắt.

Vì vậy, với suy nghĩ đó, việc hack chúng ta phải thực hiện trong jQueryUI 1.8 được thay thế bằng:

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

Ví dụ: http://jsfiddle.net/andrewwhitaker/x5q6Q/


jQueryUI 1.8

Tôi không thể tìm thấy cách đơn giản để thực hiện việc này với API jQueryUI, tuy nhiên, bạn có thể thay thế autocomplete._responsehàm bằng hàm của riêng mình, rồi gọi hàm jQueryUI mặc định ( được cập nhật để mở rộng prototypeđối tượng của tự động hoàn thành ) :

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

Và sau đó liên kết một trình xử lý sự kiện với autocompletesearchcompletesự kiện (nội dung là kết quả của tìm kiếm, một mảng):

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

Điều đang xảy ra ở đây là bạn đang lưu responsehàm của autocomplete vào một biến ( __response) và sau đó sử dụng applyđể gọi lại nó. Tôi không thể tưởng tượng được bất kỳ tác động xấu nào từ phương thức này vì bạn đang gọi phương thức mặc định. Vì chúng tôi đang sửa đổi nguyên mẫu của đối tượng, điều này sẽ hoạt động đối với tất cả các tiện ích con tự động hoàn thành.

Đây là một ví dụ hoạt động : http://jsfiddle.net/andrewwhitaker/VEhyV/

Ví dụ của tôi sử dụng một mảng cục bộ làm nguồn dữ liệu, nhưng tôi không nghĩ điều đó nên quan trọng.


Cập nhật: Bạn cũng có thể bao bọc chức năng mới trong tiện ích con của chính nó, mở rộng chức năng tự động hoàn thành mặc định:

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

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

Thay đổi cuộc gọi của bạn từ .autocomplete({...});thành:

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

Và sau đó liên kết với autocompletesearchcompletesự kiện tùy chỉnh sau:

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

Xem ví dụ tại đây : http://jsfiddle.net/andrewwhitaker/VBTGJ/


Vì câu hỏi / câu trả lời này đã thu hút một số sự chú ý, tôi nghĩ tôi sẽ cập nhật câu trả lời này bằng một cách khác để thực hiện điều này. Phương pháp này hữu ích nhất khi bạn chỉ có một tiện ích con tự động hoàn thành trên trang. Cách làm này có thể được áp dụng cho tiện ích con tự động hoàn thành sử dụng nguồn cục bộ hoặc từ xa:

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

Bên trong iflà nơi bạn sẽ đặt logic tùy chỉnh của mình để thực thi khi không có kết quả nào được phát hiện.

Ví dụ: http://jsfiddle.net/qz29K/

Nếu bạn đang sử dụng nguồn dữ liệu từ xa, hãy nói điều gì đó như sau:

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

Sau đó, bạn sẽ cần thay đổi mã của mình để tự thực hiện cuộc gọi AJAX và có thể phát hiện khi có 0 kết quả trả về:

$("#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, có ý kiến ​​gì về cách tôi có thể truy cập các phần tử trong mảng "nội dung" bằng jQuery không ???
Bongs

1
@Bongs: Bạn sẽ có thể truy cập trực tiếp bởi chỉ sốcontents[0]
Andrew Whitaker

Trên thực tế, vấn đề là mảng nội dung đã được điền với tên người dùng và hình ảnh của nó, và không thể truy cập nó bằng cách chỉ định giá trị chỉ mục. Nhưng đã tìm ra giải pháp. Phải đề cập đến như thế nào, nội dung [i] .user.username ... :) cảm ơn cho trả lời và giải pháp tuyệt vời ...
bongs

Giải pháp trên cũng hoạt động tốt cho tính năng tự động hoàn thành PrimeFaces (2.2.x) dựa trên cùng một plugin jQuery.
wrschneider

3
Trong JqueryUI 1.8.19, hàm _response được đổi tên thành __response. ( goo.gl/zAl88 ). Vì vậy, $ .ui.autocomplete.prototype._response trở thành $ .ui.autocomplete.prototype .__ phản ứng
crazyphoton

6

Mọi người dường như đang bỏ qua cách dễ dàng, có sẵn: sử dụng sự kiện message: 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")
    }
  }
})

Tính năng này đã được thêm vào jQuery 1.9, như một tính năng thử nghiệm ( được mô tả ở đây ). Vào tháng 7 năm 2017, nó vẫn chưa được ghi lại trong API .


2

Nếu bạn đang sử dụng nguồn dữ liệu từ xa (như cơ sở dữ liệu MySQL, PHP hoặc bất kỳ thứ gì ở phía máy chủ), có một số cách khác dễ dàng hơn để xử lý tình huống khi không có dữ liệu nào để trả về máy khách (mà không cần bất kỳ hack hoặc thay đổi mã giao diện người dùng mã lõi).

Tôi sử dụng PHP và MySQL làm nguồn dữ liệu từ xa và JSON để truyền thông tin giữa chúng. Trong trường hợp của tôi, tôi dường như gặp lỗi ngoại lệ jQuery nếu yêu cầu JSON không nhận được một số loại phản hồi từ máy chủ, vì vậy tôi thấy dễ dàng hơn khi chỉ trả lại phản hồi JSON trống từ phía máy chủ khi không có dữ liệu và sau đó xử lý máy khách phản hồi từ đó:

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

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

Một cách khác sẽ là trả về một cờ trong phản hồi từ máy chủ để chỉ ra rằng không có dữ liệu phù hợp và thực hiện hành động phía máy khách dựa trên sự hiện diện (và hoặc giá trị) của cờ trong phản hồi. Trong trường hợp này, phản hồi của máy chủ sẽ như sau:

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

Sau đó, dựa trên cờ này các hành động có thể được thực hiện phía máy khách:

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

Sau khi khởi tạo phần tử tự động hoàn thành của bạn, hãy đặt tùy chọn thông báo nếu bạn muốn sử dụng các khoảng thời gian mặc định cho chỉ báo thông báo:

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

LƯU Ý : Đây là một API thử nghiệm (không được ghi lại). Các nhà phát triển jQuery UI vẫn đang nghiên cứu một giải pháp đầy đủ cho thao tác chuỗi và quốc tế hóa.


0

Sau nhiều giờ chơi, cuối cùng tôi đã tìm thấy một thủ thuật để hiển thị No match foundtrong tự động hoàn thành jQuery. Nhìn vào đoạn mã trên và chỉ cần thêm một div, trong trường hợp của tôi #ulNoMatchvà kiểu của nó được đặt thành displap:none. Trong phương thức gọi lại thành công, hãy kiểm tra xem mảng được trả về có chưa length == 0. Nếu nó ở đó bạn đi, bạn đã làm một ngày của bạn! :)

<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

Tôi không hiểu tại sao sourcetham số với lệnh gọi lại tùy chỉnh là không đủ:

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

Câu trả lời này không đóng góp gì mới, câu trả lời được chấp nhận có cùng mã.
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);
                            }
                            });
                        },

Câu trả lời này không đóng góp gì mới, câu trả lời được chấp nhận có cùng mã.
Martin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.