仅当光标在输入中时如何显示 easyautocomplete 对话框

How show easyautocomplete dialog only if cursor is in input

我正在尝试对我的输入设置 easyautocomplete。我从 ajax json 获得的数据集有一些延迟。如果用户速度太快,例如写 "Adam" 并按下 tab,光标会跳到下一个输入,但是在 easyautocomplete 之后会显示上一个输入的对话框并且不会隐藏它。有什么方法可以仅在输入光标时显示 easyautocomplete 对话框?

var options = {
    minCharNumber: 3,
    url: function(phrase) {
        return "data?q=" + phrase;
    },

    getValue: function(element) {

        return element.surname + " " + element.name;
    },

    template: {
        type: "description",
        fields: {
            description: "phone"
        }
    },

    ajaxSettings: {
        dataType: "json",
        method: "POST",
        data: {
            dataType: "json"
        }
    },

    list: {
        onClickEvent: function() {
            /*Some action*/
        },
        hideAnimation: {
            type: "slide", //normal|slide|fade
            time: 400,
            callback: function() {}
        }
    },
    requestDelay: 400
};

$(".autoComplete").easyAutocomplete(options);

最小、完整、可验证、示例

为了轻松查看此结果,您必须打开开发工具并限制网络流量,这样 ajax 连接需要一点时间

Here's a Demo of the issue in jsFiddle

处理库事件(不起作用)

我最初的想法是,您可以在触发的某些 EAC lifecycle events 期间处理此问题,例如 onLoadEventonShowListEvent:

var 选项 = {
  url: "https://raw.githubusercontent.com/KyleMit/libraries/gh-pages/libraries/people.json",
  获取值:"name",
  列表: {
    比赛: {
      启用:真
    },
    <b>onLoadEvent</b>: 函数() {
      console.log('LoadEvent', 这个)
    },
    <b>onShowListEvent</b>: 函数() {
      console.log('ShowListEvent', 这个)
    }
  },
};

但是,这些方法似乎没有提供改变控制流和防止未来事件的选项

更新源代码(有效)

查看库的源代码,Easy AutoComplete 执行以下操作...

  1. Handles keyup events

  2. 然后调用 loadData

  3. 这会触发 AJAX request with the provided URL

    根据网络和服务器速度,在第 4 步之前可能会经过任何时间,输入可能会失去焦点

  4. 一旦 ajax 承诺被 returned,将调用 showContainer()

  5. 哪个triggers the "show.eac" event在容器上

  6. 然后opens the list选择动画

在第 6 步中,我们可以添加最后一项检查以确认所选输入在实际打开之前仍然具有焦点,如下所示:

$elements_container.on("show.eac", 函数() {

  <b>// 如果输入失去焦点,不显示容器
  如果 (!$field.is(":focus")) {return}</b>

  // ... 方法的其余部分 ... 

Here's a working demo in Plunker 在新文件中修改库的源代码

不幸的是,这不是一个很好的做法,因为它让您容易受到未来更改的影响,并将 lib 维护的所有权转移到您的代码库。但它确实有效。

我根据提议的更改创建了 Pull Request #388,因此希望库本身的长期修复在将来的某个时候可用。

包装器(目前推荐)

如果您不想弄乱第三方代码,可以使用一些奇怪的解决方法来扰乱内部执行。我们无法修改 showContainer 方法,因为它在闭包中。

我们可以在 show.eac 事件上添加另一个侦听器,这样我们就可以成为事件管道的一部分,但是这里也存在一些挑战。理想情况下,我们希望在执行库处理程序之前触发并有条件地停止传播。但是,初始化 EAC 将 a) 创建我们必须监听的容器,并且 b) 附加一个事件监听器。

Note: Event handlers in jQuery are fired in the order they are attached!

所以,我们必须等到 lib 加载后才能附加我们的处理程序,但这意味着我们只会在列表已经显示后触发。

从问题 How to order events bound with jQuery 中,我们可以深入了解 jQuery 内部结构和 re-order 附加事件,以便我们可以在调用库的处理程序之前触发我们的处理程序。看起来像这样:

$._data(element, 'events')["show"].reverse()

Note: Both e.stopPropagation() and e.preventDefault() won't work since they prevent future events; instead we need to take more immediate action with e.stopImmediatePropagation()

所以包装器看起来像这样:

$("#countries").easyAutocomplete(options);

$(".easy-autocomplete-container").on("show.eac", function(e) {
  var inputId = this.id.replace('eac-container-','')
  var isFocused = $("#"+inputId).is(":focus")
  if (!isFocused ) {
     e.stopImmediatePropagation()
  }
});

$(".easy-autocomplete-container").each(function() {
  $._data(this, 'events')["show"].reverse()
})

Here's a working demo in CodePen