I'm trying set easyautocomplete on my input. Dataset i am geting from ajax json and there is some delay. If user is too fast and writes for example "Adam" and pushes tab, cursor skips to next input, but after easyautocomplete shows dialog on previous input and doesn´t hide it. Is there any way how to show easyautocomplete dialog only when i have cursor in input?

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

Minimum, Complete, Verifiable, Example

In order to easily see this result, you'll have to open up your dev tools and throttle your network traffic so the ajax connection takes a little while

Here's a Demo of the issue in jsFiddle

Throttle Network Demo

Handling Library Events (Doesn't Work)

My initial thought was you could handle this during some of the EAC lifecycle events that fired, like the onLoadEvent or onShowListEvent:

<!-- language: lang-js --> <pre><code>var options = { url: "https://raw.githubusercontent.com/KyleMit/libraries/gh-pages/libraries/people.json", getValue: "name", list: { match: { enabled: true }, <b>onLoadEvent</b>: function() { console.log('LoadEvent', this) }, <b>onShowListEvent</b>: function() { console.log('ShowListEvent', this) } }, };</code></pre>

However, these methods don't seem to provide an option to alter the control flow and prevent future events

Updating Source Code (Works)

Peeking into the library's source code, Easy AutoComplete does the following ...

  1. Handles keyup events

  2. Which then calls loadData

  3. Which fires an AJAX request with the provided URL

    <sup>depending on the network and server speed, any amount of time can pass before step 4, and the input could lose focus</sup>

  4. Once the ajax promise is returned, will call showContainer()

  5. Which triggers the "show.eac" event on the container

  6. Which then opens the list with the selected animation

During step 6, we could add one last check to confirm the selected input still has focus before actually opening, which would look like this:

<!-- language: lang-js --> <pre><code>$elements_container.on("show.eac", function() { <b>// if input has lost focus, don't show container if (!$field.is(":focus")) {return}</b> // ... rest of method ... </code></pre>

Here's a working demo in Plunker which modifies the library's source code in a new file

Unfortunately, that's not a great practice as it leaves you fragile to future changes and transfers ownership of the lib maintenance to your codebase. But it does work.

I created Pull Request #388 with the proposed changes, so hopefully a long term fix within the library itself will be available at some point in the future.

Wrapper (Recommended for now)

If you don't want to muck with third party code, there are some weird workarounds to mess with the internal execution. We can't modify the showContainer method since it's inside a closure.

We can add another listener on the show.eac event so we can be a part of the event pipeline, however there are some challenges here too. Ideally, we'd like to fire before the library handler is executed and conditionally stop propagation. However, initializing EAC will both a) create the container we have to listen to and also b) attach an event listener.

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

So, we have to wait until after the lib loads to attach our handler, but that means we'll only fire after the list is already displayed.

From the question How to order events bound with jQuery, we can poke into the jQuery internals and re-order attached events so we can fire our handler before the library's handler is called. That'll look like this:

$._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()

So the wrapper would look like this:

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