ตรวจไม่พบผลลัพธ์ในการเติมข้อความอัตโนมัติ jQuery UI


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

คำตอบ:


201

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([]);
            }
        });
    }
});

@ แอนดรูมีความคิดว่าฉันจะเข้าถึงองค์ประกอบในอาร์เรย์ "เนื้อหา" โดยใช้ jQuery ได้อย่างไร ???
ป๊อก

1
@Bongs: คุณควรจะสามารถเข้าถึงได้โดยตรงโดยดัชนีcontents[0]
Andrew Whitaker

จริงๆแล้วสิ่งนั้นคืออาร์เรย์เนื้อหาถูกเติมด้วยชื่อผู้ใช้และรูปภาพและไม่สามารถเข้าถึงได้โดยการระบุค่าดัชนี แต่คิดหาวิธีแก้ปัญหา ต้องพูดถึงเช่นเนื้อหา [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

ดูเหมือนทุกคนจะไม่สนใจวิธีง่ายๆในตัว: ใช้เหตุการณ์ข้อความ: 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หรืออะไรก็ตามในฝั่งเซิร์ฟเวอร์) มีวิธีอื่น ๆ อีกสองสามวิธีในการจัดการกับสถานการณ์เมื่อไม่มีข้อมูลที่จะกลับไปยังไคลเอนต์ แฮ็กหรือการเปลี่ยนแปลงรหัส UI ของรหัสหลัก)

ฉันใช้ 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 UI ยังคงตรวจสอบโซลูชันเต็มรูปแบบสำหรับการจัดการสตริงและการทำให้เป็นสากล


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

คำตอบนี้ไม่ได้มีส่วนช่วยอะไรใหม่คำตอบที่ยอมรับมีรหัสเดียวกัน
Martin

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

คำตอบนี้ไม่ได้มีส่วนช่วยอะไรใหม่คำตอบที่ยอมรับมีรหัสเดียวกัน
Martin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.