Tidak mendeteksi hasil pada pelengkapan otomatis jQuery UI


89

Sebelum Anda mengarahkan saya ke mereka, ya, saya telah meninjau setengah lusin posting tentang topik ini, tetapi saya masih bingung mengapa ini tidak berhasil.

Tujuan saya adalah untuk mendeteksi ketika pelengkapan otomatis memberikan 0 hasil. Berikut kodenya:

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

  })
 }
}); 

Pencarian itu sendiri berfungsi dengan baik, saya bisa mendapatkan hasil yang muncul tanpa masalah. Seperti yang saya pahami, saya harus bisa menghentikan hasil dengan penangan pelengkapan otomatis ("hasil"). Dalam hal ini, tidak pernah menyala sama sekali. (Bahkan peringatan umum atau console.log yang tidak mereferensikan jumlah hasil tidak pernah diaktifkan). Penangan peristiwa terbuka menunjukkan jumlah hasil yang benar (bila ada hasil), dan penangan peristiwa penelusuran dan penutupan melaporkan ukuran hasil yang selalu tertinggal satu langkah.

Saya merasa seperti saya kehilangan sesuatu yang jelas dan mencolok di sini tetapi saya tidak melihatnya.


Sepertinya tidak ada cara mudah untuk melakukannya dengan widget pelengkapan otomatis yang didorong oleh data sisi klien. Apakah menggunakan sumber jarak jauh untuk widget merupakan pilihan?
Andrew Whitaker

Jawaban:


200

jQueryUI 1.9.0

jQueryUI 1.9 telah memberkati widget pelengkapan otomatis dengan responseacara tersebut, yang dapat kita manfaatkan untuk mendeteksi jika tidak ada hasil yang dikembalikan:

Dipicu setelah pencarian selesai, sebelum menu ditampilkan. Berguna untuk manipulasi data saran lokal, yang tidak memerlukan callback opsi sumber kustom. Peristiwa ini selalu dipicu saat penelusuran selesai, meskipun menu tidak akan ditampilkan karena tidak ada hasil atau Pelengkapan Otomatis dinonaktifkan.

Jadi, dengan pemikiran tersebut, peretasan yang harus kami lakukan di jQueryUI 1.8 diganti dengan:

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

Contoh: http://jsfiddle.net/andrewwhitaker/x5q6Q/


jQueryUI 1.8.0

Saya tidak dapat menemukan cara langsung untuk melakukan ini dengan API jQueryUI, namun, Anda dapat mengganti autocomplete._responsefungsinya dengan milik Anda sendiri, dan kemudian memanggil fungsi jQueryUI default ( diperbarui untuk memperluas objek pelengkapan otomatis prototype) :

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

Dan kemudian ikat event handler ke autocompletesearchcompleteevent (isinya adalah hasil pencarian, sebuah array):

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

Apa yang terjadi di sini adalah Anda menyimpan responsefungsi pelengkapan otomatis ke variabel ( __response) dan kemudian menggunakannya applyuntuk memanggilnya lagi. Saya tidak bisa membayangkan efek buruk dari metode ini karena Anda memanggil metode default. Karena kami memodifikasi prototipe objek, ini akan berfungsi untuk semua widget pelengkapan otomatis.

Berikut adalah contoh yang berfungsi : http://jsfiddle.net/andrewwhitaker/VEhyV/

Contoh saya menggunakan array lokal sebagai sumber data, tapi menurut saya itu tidak penting.


Pembaruan: Anda juga dapat menggabungkan fungsionalitas baru dalam widgetnya sendiri, memperluas fungsionalitas pelengkapan otomatis default:

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

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

Mengubah panggilan Anda dari .autocomplete({...});menjadi:

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

Lalu ikat ke autocompletesearchcompleteacara khusus nanti:

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

Lihat contohnya di sini : http://jsfiddle.net/andrewwhitaker/VBTGJ/


Karena pertanyaan / jawaban ini mendapat perhatian, saya pikir saya akan memperbarui jawaban ini dengan cara lain untuk mencapai ini. Metode ini paling berguna jika Anda hanya memiliki satu widget pelengkapan otomatis di halaman. Cara melakukannya ini dapat diterapkan ke widget pelengkapan otomatis yang menggunakan sumber jarak jauh atau lokal:

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

Di dalamnya ifadalah tempat Anda akan menempatkan logika kustom Anda untuk dieksekusi ketika tidak ada hasil yang terdeteksi.

Contoh: http://jsfiddle.net/qz29K/

Jika Anda menggunakan sumber data jarak jauh, katakan sesuatu seperti ini:

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

Kemudian Anda harus mengubah kode Anda sehingga Anda membuat panggilan AJAX sendiri dan dapat mendeteksi ketika 0 hasil kembali:

$("#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, tahu bagaimana saya dapat mengakses elemen dalam array "konten" menggunakan jQuery ???
Bongs

1
@Bong: Anda seharusnya dapat mengaksesnya secara langsung dengan indekscontents[0]
Andrew Whitaker

Sebenarnya masalahnya adalah array konten diisi dengan nama pengguna dan gambarnya, dan tidak dapat mengaksesnya dengan menentukan nilai indeks. Tapi menemukan solusinya. Harus menyebutkan seperti, isinya [i] .user.username ... :) terima kasih atas balasannya dan solusi yang luar biasa ...
Bongs

Solusi di atas juga berfungsi dengan baik untuk pelengkapan otomatis PrimeFaces (2.2.x) yang didasarkan pada plugin jQuery yang sama.
wrschneider

3
Di JqueryUI 1.8.19, fungsi _response diubah namanya menjadi __response. ( goo.gl/zAl88 ). Jadi, $ .ui.autocomplete.prototype._response menjadi $ .ui.autocomplete.prototype .__ response
crazyphoton

6

Semua orang tampaknya mengabaikan cara bawaan yang mudah: gunakan acara 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")
    }
  }
})

Fitur ini ditambahkan di jQuery 1.9, sebagai fitur eksperimental ( dijelaskan di sini ). Per Juli 2017, ini belum didokumentasikan di API .


2

Jika Anda menggunakan sumber data jarak jauh (seperti database MySQL, PHP , atau apa pun di sisi server), ada beberapa cara bersih lainnya untuk menangani situasi ketika tidak ada data untuk dikembalikan ke klien (tanpa perlu hack atau perubahan kode UI kode inti).

Saya menggunakan PHP dan MySQL sebagai sumber data jarak jauh dan JSON untuk menyampaikan informasi di antara keduanya. Dalam kasus saya, saya sepertinya mendapatkan kesalahan pengecualian jQuery jika permintaan JSON tidak mendapatkan semacam respons dari server, jadi saya merasa lebih mudah untuk mengembalikan respons JSON kosong dari sisi server ketika tidak ada data dan kemudian menangani klien respon dari sana:

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

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

Cara lain adalah dengan mengembalikan tanda dalam respons dari server untuk menunjukkan bahwa tidak ada data yang cocok dan melakukan tindakan di sisi klien berdasarkan keberadaan (dan atau nilai) tanda dalam respons. Dalam hal ini respons server akan menjadi seperti:

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

Kemudian berdasarkan aksi bendera ini dapat dilakukan di sisi klien:

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

Setelah menginisialisasi elemen pelengkapan otomatis Anda, setel opsi pesan jika Anda ingin menggunakan span default untuk indikasi pesan:

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

CATATAN : Ini adalah API eksperimental (tidak didokumentasikan). Pengembang jQuery UI masih menyelidiki solusi lengkap untuk manipulasi string dan internasionalisasi.


0

Setelah berjam-jam bermain, saya akhirnya menemukan trik untuk ditampilkan No match founddi jQuery autocomplete. Lihat kode di atas dan cukup tambahkan a div, dalam kasus saya #ulNoMatchdan set gayanya ke displap:none. Dalam metode sukses panggilan balik, periksa apakah array yang dikembalikan memiliki length == 0. Jika itu ada, Anda membuat hari Anda menyenangkan! :)

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

Jawaban ini tidak memberikan kontribusi yang baru, jawaban yang diterima memiliki kode yang sama.
Martin

0

Saya tidak mengerti mengapa sourceparameter dengan callback khusus tidak cukup:

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

Jawaban ini tidak memberikan kontribusi yang baru, jawaban yang diterima memiliki kode yang sama.
Martin
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.