JQuery 自动完成对第一个按键事件不起作用(源是一个数组)

Posted

技术标签:

【中文标题】JQuery 自动完成对第一个按键事件不起作用(源是一个数组)【英文标题】:JQuery autocomplete doesn't work on the first keypress event (the source is an array) 【发布时间】:2018-07-04 18:57:39 【问题描述】:

我正在像 Google 一样创建搜索结果自动填充功能。

自动完成的结果(或源)将是一个动态数组(该数组是使用从$.ajax 调用中的URL 属性访问的对象创建的)并且每个keypress 上的元素变化非常快事件。

我的意思很简单:

    我们有一个变量autocompleteResults$.ajax成功回调函数中,我们将此变量分配给空数组:autocompleteResults = []

    在此之后,我们正在执行$.each() 函数:

    $.each(d.query.pages, function(i) 
      autocompleteResults.push(d.query.pages[i].title);
    );  
    
    // d.query.pages - JSON object from the success callback (success: function(d) ...
    

    我们在成功回调结束时调用callback(autocompleteResults)

    调用此函数有效,数组返回正确:

    getAutocompleteResults(function() 
      console.log(autocompleteResults);
    );
    

    那么在同一个范围内:

    $("#search").autocomplete(source: autocompleteResults,...);
    

    而且它只在我第二次输入内容时起作用。


使用图片快速概览:

    先看一下刚刚重新加载后的页面: 让我们在输入字段中输入一些内容(例如“a”): 如上图所示,我们没有自动完成结果(“a”结果只是 JS 创建的表格,与此问题无关)。让我们尝试使用键盘上的退格按钮删除“a”字符: 我们得到了与第一张图片相同的结果。但是等等,有些事情发生了变化。让我们尝试输入与第二张图片中相同的密钥,看看我们得到了什么: 奇迹!在上图中,一切都是它应该的样子。问题是只有在第二次尝试在字段中输入内容后才能获得此结果。它应该在第一次尝试时起作用。

我关于这个问题的所有研究结果:

    如果不将自动完成功能放置在 keypress 事件函数中,则它可以完美运行。但是,在这种情况下,我们得到一次结果,然后它停止响应未来类型(输入“a” - 5 个结果,输入“aa” - 与“a”相同的结果并且它不响应。

    我想我应该使用$( ".selector" ).autocomplete( "search", "" ); 再次更改源,如here 所述,但我不确定它是否能解决这个问题。

    我的代码以某种方式堆积了 AJAX 请求,并且多次重复相同的请求。我该如何解决这个问题?:

    像这样的线程没有帮助: jQuery UI autocomplete with JSON, jQuery autocomplete with callback ajax json, Jquery Autocomplete Search with Ajax Request as sourcedata, https://forum.jquery.com/topic/autocomplete-with-ajax-and-json-not-working。


要查看完整的项目代码,请访问此处: https://codepen.io/Kestis500/pen/PErONL?editors=0010

或者使用代码的小sn-p(这样你就可以看到问题发生的最重要的部分):

$(function() 
  var autocompleteResults;
  var changeText2 = function(e) 
    var request = $("input").val() + String.fromCharCode(e.which);
    $("#instant-search").text(request);

    var getAutocompleteResults = function(callback) 
      $.ajax(
        url: "https://en.wikipedia.org/w/api.php?action=query&format=json&gsrlimit=5&generator=search&origin=*&gsrsearch=" + $('#instant-search').text(),
        success: function(d) 

          autocompleteResults = [];
          $.each(d.query.pages, function(i) 
            autocompleteResults.push(d.query.pages[i].title);
          );

          callback(autocompleteResults);
        ,
        datatype: "json",
        cache: false
      );
    ;

    getAutocompleteResults(function() 
      console.log(autocompleteResults);
    );




    $("#search").autocomplete(
      source: autocompleteResults,
      response: function() 
        if (
          $("#instant-search")
          .text()
        ) 
          $("table").css("display", "table");
        
      ,
      close: function() 
        if (!$(".ui-autocomplete").is(":visible")) 
          $(".ui-autocomplete").show();
        
      ,
      appendTo: ".input",
      focus: function(e) 
        e.preventDefault();
      ,
      delay: 0
    );


  ;

  var changeText1 = function(e) 
    if (
      /[-a-z0-90áãâäàéêëèíîïìóõôöòúûüùçñ!@#$%^&*()_+|~=`\[\]:";'<>?,.\s\/]+/gi.test(
        String.fromCharCode(e.which)
      )
    ) 
      $("input").on("keypress", changeText2);
    



    // THIS PART HAS NOTHING TO DO WITH THIS PROBLEM AND DELETING THIS WOULD MAKE A TABLE CREATED BY THE html TO NOT FUNCTION
    var getInputSelection = function(input) 
      var start = 0,
        end = 0;
      input.focus();
      if (
        typeof input.selectionStart == "number" &&
        typeof input.selectionEnd == "number"
      ) 
        start = input.selectionStart;
        end = input.selectionEnd;
       else if (document.selection && document.selection.createRange) 
        var range = document.selection.createRange();
        if (range) 
          var inputRange = input.createTextRange();
          var workingRange = inputRange.duplicate();
          var bookmark = range.getBookmark();
          inputRange.moveToBookmark(bookmark);
          workingRange.setEndPoint("EndToEnd", inputRange);
          end = workingRange.text.length;
          workingRange.setEndPoint("EndToStart", inputRange);
          start = workingRange.text.length;
        
      
      return 
        start: start,
        end: end,
        length: end - start
      ;
    ;

    switch (e.key) 
      case "Backspace":
      case "Delete":
        e = e || window.event;
        var keyCode = e.keyCode;
        var deleteKey = keyCode == 46;
        var sel, deletedText, val;
        val = this.value;
        sel = getInputSelection(this);
        if (sel.length) 
          // 0 kai paprastai trini po viena o 1 ar daugiau kai select su pele trini
          $("#instant-search").text(
            val.substr(0, sel.start) + val.substr(sel.end)
          );
         else 
          $("#instant-search").text(
            val.substr(0, deleteKey ? sel.start : sel.start - 1) +
            val.substr(deleteKey ? sel.end + 1 : sel.end)
          );
        
        break;
      case "Enter":
        if (
          $("#instant-search")
          .text()
          .trim()
        ) 
          console.log("Redirecting...");
        
        break;
    

    if (!$("#instant-search")
      .text()
      .trim()
    ) 
      $("table, .ui-autocomplete").hide();
    
  ;

  $("input").on("keydown", changeText1);










  $("input").on("input", function(e) 
    $("#instant-search").text($("#search").val());
    if (
      $("#instant-search")
      .text()
      .trim()
    ) 
      $('table').css('display', 'table');
     else 
      $("table").hide();
    
  );
);
html,
body 
  height: 100%;
  width: 100%;


body 
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  background-color: #000428;
  /* fallback for old browsers */
  background-image: -webkit-linear-gradient(to right, #004e92, #000428);
  /* Chrome 10-25, Safari 5.1-6 */
  background-image: linear-gradient(to right, #004e92, #000428);
  /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */


.v-container 
  display: table;
  height: 100%;
  width: 100%;


.v-content 
  display: table-cell;
  vertical-align: middle;


.text-center 
  text-align: center;


h1 
  color: #fff;


.input 
  overflow: hidden;
  white-space: nowrap;


.input input#search 
  width: calc(100% - 30px);
  height: 50px;
  border: none;
  font-size: 10pt;
  float: left;
  color: #4f5b66;
  padding: 0 15px;
  outline: none;


.input button.icon 
  border: none;
  height: 50px;
  width: 50px;
  color: #4f5b66;
  background-color: #fff;
  border-left: 1px solid #ddd;
  margin-left: -50px;
  outline: none;
  cursor: pointer;
  display: none;
  -webkit-transition: background-color .5s;
  transition: background-color .5s;


.input button.icon:hover 
  background-color: #eee;


.ui-autocomplete 
  list-style: none;
  background-color: #fff;
  -webkit-user-select: none;
  user-select: none;
  padding: 0;
  margin: 0;
  width: 100% !important;
  top: auto !important;
  display: table;
  table-layout: fixed;


.ui-helper-hidden-accessible 
  display: none;


.autocomplete-first-field 
  width: 15%;
  display: inline-block;


.autocomplete-second-field 
  width: 85%;
  display: inline-block;
  text-align: left;
  vertical-align: middle;


.three-dots 
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;


table 
  width: 100%;
  border-spacing: 0;
  border-collapse: collapse;
  display: none;
  table-layout: fixed;


table tr 
  background-color: #fff;
  -webkit-user-select: none;
  user-select: none;


tr:first-child 
  background-color: #ffc800;
  color: #fff;


table td,
.ui-menu-item-wrapper 
  padding: 10px 0;


td:nth-child(2) 
  width: 85%;
  text-align: left;


.ui-menu-item,
table 
  cursor: pointer;


:focus 
  outline: 0;


a 
  text-decoration: none;
  color: #fff;
  position: relative;


#random-article 
  margin-bottom: 5px;


.search-results 
  background: #fff;
  margin-top: 50px;
  border-left: 0 solid;
  cursor: pointer;
  -webkit-transition: border-left .5s;
  transition: border-left .5s;


.search-results h4,
.search-results p 
  margin: 0;
  padding: 10px;


.search-results:not(:first-child) 
  margin-top: 25px;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js">
<!--<![endif]-->
<div class="v-container">
  <div class="v-content text-center">
    <div id="random-article"><a href="https://en.wikipedia.org/wiki/Special:Random">Click here for a random WikiSearch article! :)</a></div>
    <div class="input">
      <input type="text" id="search" placeholder="Search...">
      <button class="icon"><i class="fa fa-search"></i></button>

      <table>
        <tr>
          <td class="fa fa-search">
            <td id="instant-search" class="three-dots"></td>
        </tr>
      </table>
    </div>
  </div>
</div>

如果您对如何解决此问题有任何想法,我们将非常感谢您的帮助 :)

【问题讨论】:

【参考方案1】:

您已将 source: autocompleteResults, 保留在 autocompleteResults 动态变化的位置,您应该做这样的事情

source: function (request, response) 
    getAutocompleteResults(function(data)
      response(data);
    );
  ,

工作代码https://codepen.io/anon/pen/OzeQvw?editors=0010

【讨论】:

以上是关于JQuery 自动完成对第一个按键事件不起作用(源是一个数组)的主要内容,如果未能解决你的问题,请参考以下文章

jQuery 自动完成源为空

为什么我的自动完成功能不起作用?

使用 jQuery 触发按键事件的确定方法

知道为啥这个 Jquery 自动完成功能不起作用吗?

jquery UI 自动完成:我克隆的自动完成字段不起作用

我的 jquery 自动完成功能不起作用