Opened 8 years ago

Closed 7 years ago

Last modified 7 years ago

#7555 closed bug (fixed)

autoFocus randomly deletes typed characters

Reported by: feklee Owned by:
Priority: minor Milestone: 1.9.0
Component: ui.autocomplete Version: 1.8.14
Keywords: Cc:
Blocked by: Blocking:

Description

How I experienced the problem:

  1. Opened one of: IE8, Chrome 13.0, Opera 11.50 on WinXP/32
  1. Went to: http://jsbin.com/imowet
  1. Quickly typed into the input field: "java". In the input field, I saw: "j", "ja", "jav", "jaa". Notice that the "v" got deleted.

Notes:

  • Disabling "autoFocus" makes the problem go away.
  • You may want to adjust the delay and timeout. However, I was able to reproduce the problem with pretty much any combination I tried.

See also: http://forum.jquery.com/topic/autocomplete-ie7-backspace-issue#14737000002558270

Affected jQuery UI version: 1.8.14 (with jQuery 1.6.2)

Change History (28)

comment:1 Changed 8 years ago by Scott González

#7597 is a duplicate of this ticket.

comment:2 Changed 8 years ago by sexconker

Was searching high and low for this problem last week, and decided to file a bug report today. Somehow I didn't land upon this page, so I ended up making that dupe.

Good to see it's not just us. We also noticed the effect happening less frequently with higher delays, but it would still happen. The easiest way to reproduce it is to type a string in, then backspace through it (individual key presses, not holding backspace).

comment:3 Changed 8 years ago by carl@…

Found this workaround that seems to be working for me - modify the "$( ".ui-autocomplete-input" ).live( "autocompleteopen", function()" function at the very end of jQuery-ui-1.8.11.js as found here:

https://github.com/davemyers/jquery-ui-extensions/blob/master/autocomplete/jquery.ui.autocomplete.selectFirst.js

comment:4 Changed 8 years ago by jbergenthal

I've found menu.blur is the problem. It is meant to put the old value when the user presses ESC. However, menu.blur gets also called every time new data comes from the server. So in the sequence: request-new-data, user-types-something, data-response menu.blur sets the old value and what the user typed is lost.

comment:5 Changed 8 years ago by Scott González

Thanks @jbergenthal. I actually removed this code the other day, so this should be fixed. We've had a lot of trouble reproducing this bug (though we've seen it so we know it's valid). If you've been able to reliably reproduce this, can you test against master and verify that it's fixed now?

comment:6 Changed 8 years ago by Scott González

Resolution: fixed
Status: newclosed

I was able to confirm. Thanks again jbergenthal!

comment:7 Changed 8 years ago by Scott González

comment:8 Changed 7 years ago by huemorgan

The problem is not fixed. and I can reproduce it, I changed the JSbin example above a bit and was able to reproduce it easily http://jsbin.com/akalon/5/edit#preview - instructions inside

I'm using jquery-ui 1..8.16, jquery 1.7.1 but it's not working in the example with 1.8.14 and jquery 1.6.2 as well on chrome 17.0.963.79 - not that it matters ;)

the problem exist when autoFocus=true delay>=50 ms if i set delay=0 there is no problem.

the bug is the same - deleting characters randomly when a response comes back.

Please help - nothing would please me more then fixing this horrible bug

Last edited 7 years ago by huemorgan (previous) (diff)

comment:9 Changed 7 years ago by Scott González

@huemorgan. This *is* fixed. Note the milestone of 1.9, the fix does not exist in 1.8.16, so it's obviously still broken there.

comment:10 Changed 7 years ago by NielsJanssen

I'm running into the same issue. Is it possible for this fix to be merged into 1.8.19? As it seems to be a relatively minor fix for a problem which is causing me quite a headache.

comment:11 Changed 7 years ago by Scott González

Feel free to send a pull request.

comment:12 Changed 7 years ago by ninjaxify

Hey Folks,

I am using the latest version of JqueryUI(1.8.23) and this issue is still there.

This is driving me up the wall, given that the basic experience of typing text in my autocomplete active text box is not working!

If this bug is fixed, can I get a patch for this? This bugs is preventing me from using autocomplete on my production system, and a patch would be really helpful!

comment:13 in reply to:  12 Changed 7 years ago by sexconker

Replying to ninjaxify:

Hey Folks,

I am using the latest version of JqueryUI(1.8.23) and this issue is still there.

This is driving me up the wall, given that the basic experience of typing text in my autocomplete active text box is not working!

If this bug is fixed, can I get a patch for this? This bugs is preventing me from using autocomplete on my production system, and a patch would be really helpful!

See http://bugs.jqueryui.com/ticket/8234 . The race condition exists if you're using a custom source and jQueryUI 1.8.18 or earlier , though I haven't tested with 1.8.19 to verify that it's fixed.

We're still using 1.8.18 in some places and we just use the following:

source: function( request, response ) {
	$("#autocompleteInput").data('rIndex', $("#autocompleteInput").data('rIndex') + 1);

	if ( this.xhr )
		this.xhr.abort();

	this.xhr = 								

	$.ajax({
		url: "your_ajax_url",
		data: {
			data1: 1,
			data2: 2
		},

		context: {
			autocompleteRequest: $("#autocompleteInput").data('rIndex')
		},											
		
		success: function( data ) {
			if ( this.autocompleteRequest === $("#autocompleteInput").data('rIndex') ) {
				response( jQuery.map(data.split("|"), function(n, i) {
					return {
						label: n,
						value: n
					};
				}));
			}
		}
	});
},

We just add a request counter (rIndex) whenever source fires, and abort any existing requests. Then we do our new request as usual, and then on success we verify that our request index is equal to the expected value.

comment:14 Changed 7 years ago by Syryos

This is still an annoying bug and needs a fix.

Observed in jquery 1.8.2 and jquery-ui 1.9.1

Please reopen !

comment:15 Changed 7 years ago by tj.vantoll

@Syryos I cannot create this using the example originally provided using 1.9.1 - http://jsbin.com/imowet/9/edit.

If this is still a problem and you would like us to look into this we'll need a reduced test case showing the issue. To get you started, use this boilerplate: http://jsfiddle.net/ZgAqH/ Open the link and click to "Fork" (in the top menu) to get started.

comment:16 Changed 7 years ago by Syryos

I made a further analysis, conclusion so far is:

When the suggestions-callback is triggered, but a certain result is not available

for example

  • when a single server JSON response(*) is incorrect JSON format, for example missing closing bracket
  • when the server response is too slow (while the user still types in the #input field

the Return key submits or tries to submit the broken or incorrect "focus" result.

(*) for example, when the server response ist correct for "j", "ja", "java", "javas" but is broken for "jav" [sic]

  • j -> ok
  • ja -> ok
  • jav -> broken (*)
  • java -> ok
  • javas -> ok

user quickly clicks enter (user wants to submit "java" - but the response to (*) is coming later, overwrites the response to "javas" and in consequence, enter submits (*) instead of "javas"

As an ad-hoc fix I suggest - this must be done inside the autocomplete code - to always:

submit ONLY if the current input matches the response (which of course must mirror the original request string)

$("#input").val() === item.requestValue

_and_ to clear all pending ajax requests before submitting again. (Perhaps, you do not understand what I mean, then I will reformulate.)

When I have time, I will look into the code and propose a patch.

Last edited 7 years ago by Syryos (previous) (diff)

comment:17 Changed 7 years ago by mikesherov

Milestone: 1.9.0
Resolution: fixed
Status: closedreopened

Syryos, thanks for the persistence! I'll reopen this considering you're going to propose a patch.

comment:18 Changed 7 years ago by mikesherov

Milestone: 1.10.0
Status: reopenedopen

comment:19 Changed 7 years ago by Scott González

Syryos, What do you mean by "submit"? I thought you meant form submission, but then you say that autocomplete itself should "submit only if ...".

comment:20 Changed 7 years ago by Scott González

Milestone: 1.10.01.9.0
Resolution: fixed
Status: openclosed

I'm reclosing this. Outstanding requests are aborted as soon as a new search is started and invalid responses are ignored, so I don't see how this could be happening. If you can provide a reduced test case showing the problem, feel free to let us know.

comment:21 Changed 7 years ago by Syryos

tl;dr: reason found: you can call it bug by design, or unwanted side effect reprodicible proposed fix: available. described literally; no code published yet, sorry (but follows) Pls. reopen issue

@scott.gonzales wrote

I'm reclosing this. Outstanding requests are aborted as soon as a new search is started and invalid responses are ignored (*), so I don't see how this could be happening. If you can provide a reduced test case showing the problem, feel free to let us know.

(*) my analyis based on example code like on the jqui API pages showed, that you are wrong. Each callback in its own context fires a new request, and an older request may overtake newer ones. This is the problem: a single older request which comes later overwrites in consequence the input. This happens for example while very quickly typing characters with autocomplete parameteres min=2 and delay=200.

Can I ask you to please can you leave this issue open ? Why...? Let me explain.

I know, you want to see a patch. I will deliver such a patch, and a working example but haven't the time at the moment. But the good news is, that I now could finally solve the issue by applying two fixes !

In my environment, I was able to fully reproduce the effect of "autoFocus randomly deletes typed characters". I found the reason and a solution in the client code.

Allow me first to explain the patch in words (bear with me; a description in words may be difficult to understand). Later (may be mid December 2012), I will publish the code, no cookie-licking, promised.

Analysis:

I found, that indeed my analysis was correct. that it is a race condition:

when the server's response for a previous partial search (example: "jav" <-> old response) is coming after the response of current input "java" - then the old response - the first ajax is not killed - overwrites the new one.

This *looks* like "autoFocus randomly deletes characters*, but it is not. Its only reason is that an older server response "overtakes" the current (last) query, and this older server response updated the input div. As you usually type an increasing number of characters, this means, that an "older" server response corresponds to less characters then you have typed --> resulting in the effect and issue.

ad-hoc fix:

I could fix this behaviour by expressly deleting _any_ pending ajax request before submitting the new subquery.

A second fix was required for the autofocus=true case: I make now sure that the current $("#input").val() is now always immediately updated from the corresponding server response - when it returns, This overwrites not the elements in the ui-list but only as said the exact response to the user's input.

Proposed:

I will try to apply a correct fix in the autocomplete code itself, if this is possible.

comment:22 Changed 7 years ago by Scott González

We definitely need proof of this, not just you saying that it's a bug. Here's the code that disproves what you're saying: https://github.com/jquery/jquery-ui/blob/3c2acc322782cc08e575405f8123029342e33542/ui/jquery.ui.autocomplete.js#L417 Old requests cannot overwrite new requests as there's a unique id attached to every request and only the most recent request is processed.

Please show code that proves what you're saying. If you can do that, we'll open this bug or file a new one. Until there's proof, this will stay closed.

comment:23 Changed 7 years ago by Syryos

The core of my reliable solution (ad-hoc fix) is

var ajax;
...

//attach autocomplete
$("#input").autocomplete({
					
  //define callback to format results
  source: function(req, callback){

    //pass request to server
    if (typeof ajax != 'undefined') ajax.abort(); // stop any previous i.e. may be pending ajax requests
    ajax = $.getJSON("http://server/api.php?callback=?", req, function( responseData ) {

      ....

    }),

  ...

  select: function( event, ui ) {

    // query the server again for the current selection

    // overwrite #input with the (echoed) response from the server

    // the response comprises (echoed as additional element in the server json response) the input value
    // on which the select event was fired

    // in that way I can make 100% sure that the input string is now
    // exactly the same as it was when the user selected an item

    // code follows
  });

Last edited 7 years ago by Syryos (previous) (diff)

comment:24 Changed 7 years ago by Syryos

jquery team: you should perhaps try with lame (or differently quick) server responses, let's say responses which need 1 second and the next response takes 500ms, the next 1s. This will make the effect apparent.

Last edited 7 years ago by Syryos (previous) (diff)

comment:25 Changed 7 years ago by Syryos

It has also to do with the "select" callback and a wrong (i.e. presently not corresponding to #input) ui.item.value under the following conditions:

  • fast typing of characters
  • autoFocus == true
  • slow server reponse

comment:26 Changed 7 years ago by Scott González

@Syryos This appears to be specific to your use case, which is highly uncommon. Now that you've shows part of your code it's clear that: 1) You're not using the built-in ajax requests; 2) You're triggering a search in response to a search. Please stop posting on this ticket and file a new ticket. However, I urge you not to open the new ticket until you can provide a reduced test case that shows the problem exists.

comment:27 Changed 7 years ago by philios33

As jbergenthal says, the problem is caused by the autoFocus option. It will call a hover event on the first menu item after rendering a new menu. Unfortunately upon activating the item, the menu calls deactivate function (first line in activate function) which indeed resets the value in the input box since it triggers a blur.

It only happens if a character is typed AFTER rendering of the data has started but BEFORE the blur function is called. Since the logic in the blur functionality is triggered to be executed in another thread it is possible that by the time it runs, the user will have typed a key. This means that ui.menu thinks the data has changed and will revert it back to what it thinks is the correct data.

This hack will turn off the ui.menu reverting functionality but doesn't fix the underlying problem. You almost need to tell the menu that although you want to highlight the first item, please dont blur the menu when you activate it. I will leave it up to you guys to fix but I suggest removing the deactivate call from the activate function of ui.menu.

//This is a fix for the autoFocus bug
$.widget("ui.menu", $.ui.menu, {
	deactivate: function() {
		if (!this.active) { return; }
		this.active.children("a")
		.removeClass("ui-state-hover")
		.removeAttr("id");
		//DONT DO A BLUR
		//this._trigger("blur");
		this.active = null;
	}
});

@scott.gonzalez The use case described by Syryos is actually quite common. The autocomplete code allows you to override the source function anyway, so I dont see a problem of doing e.g. an async ajax call such as google geocode inside the source function.

comment:28 Changed 7 years ago by Scott González

@philios33 What do you mean by "It will call a hover event on the first menu item" There's no such thing as a hover event, and while 1.8.x used to trigger a synthetic mouseover event, we stopped doing that in 1.9.0.

As for as how common Syryos use case is: I've never seen this behavior, can you point me to some examples? My comment about the custom source is that he wasn't providing any useful information. He has a very complex implementation and wasn't providing any details about what he was actually doing and he couldn't provide a reduced test case showing the problem.

Can you provide a reduced test case along with steps for reproducing this? If you need to go in and modify some code so that whatever delay exists is actually very large to make it easily reproducible that's fine. Or at least point us to a specific line of code if you've tracked this down. But from your description, I still don't know what is causing what you're seeing. Autocomplete doesn't even listen to menu blur events, so I don't see how that's relevant.

Note: See TracTickets for help on using tickets.