Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception when element is removed on blur #4417

Closed
paul-f opened this issue Jun 7, 2019 · 6 comments · Fixed by #4799
Closed

Exception when element is removed on blur #4417

paul-f opened this issue Jun 7, 2019 · 6 comments · Fixed by #4799

Comments

@paul-f
Copy link

paul-f commented Jun 7, 2019

Description

Running Chrome 73.0.3683.86 on Windows 7 with jQuery 3.4.1.

jQuery tries to read a property of an undefined, causing an exception. This occurs when an element is removed when it loses focus, during a focusout handler, responding to a jQuery triggered blur() event. The three key operations are all performed via jQuery: $(element).blur(), $(element).on("focusout"), $(element).remove().

The exception occurs on line 5467; here is the code up to that line:

					dataPriv.set( this, type, saved );

					// Trigger the native event and capture its result
					// Support: IE <=9 - 11+
					// focus() and blur() are asynchronous
					notAsync = expectSync( this, type );
					this[ type ]();
					result = dataPriv.get( this, type );
					if ( saved !== result || notAsync ) {
						dataPriv.set( this, type, false );
					} else {
						result = {};
					}
					if ( saved !== result ) {

						// Cancel the outer synthetic event
						event.stopImmediatePropagation();
						event.preventDefault();
						return result.value;
					}

In the last line, result is undefined. That is because during this[ type ]() (which issues the event), the element is removed, causing jQuery to remove its saved information from dataPriv in cleanData() line 6046:
elem[ dataPriv.expando ] = undefined;

Thus, after this[ type ](), result is undefined, it does not equal saved, so the dataPriv.set() of the conditional is executed and result is left undefined. Presumably, result = () needs to be set outside the conditional. This problem is also timing-sensitive -- with the certain break points it may not occur.

This didn't happen in 3.3.1. Note also that jQuery's blur() must be used, rather than normal JS blur(), in order to go through this code path.

Link to test case

jsfiddle uses 3.3.1, so I didn't set up a test case.

*EDIT by @mgol: I wrapped code pieces in backticks to fix Markdown formatting

@mgol
Copy link
Member

mgol commented Jun 7, 2019

Thanks for the report!

We advise JS Bin for creating test cases as JSFiddle no longer supports IE; you control the whole HTML there. But even in JSFiddle you can attach a proper jQuery version by uploading a script or adding a script tag in HTML. So please still add a test case. Thanks!

@paul-f
Copy link
Author

paul-f commented Jun 7, 2019

Here's a jsbin link;
https://jsbin.com/wuqumigiya/edit?html,js,console,output

Note that the problem occurs on Chrome, not on Firefox. It is timing/sequence-related.

@gibson042
Copy link
Member

This is an unusual case, but valid. I think we want to replace return result.value with something like return result && result.value.

@timmywil timmywil added this to the 4.0.0 milestone Jul 1, 2019
@mgol
Copy link
Member

mgol commented Aug 21, 2019

As I understand it, this is a regression so we should include it in 3.4.2; updating the milestone.

@ryuran
Copy link

ryuran commented Jun 22, 2020

Hello! some news about this bug @radar @mgol ?

@mgol mgol self-assigned this Oct 8, 2020
mgol added a commit to mgol/jquery that referenced this issue Oct 9, 2020
In Chrome, if an element having a focusout handler is blurred by
clicking outside of it, it invokes the handler synchronously. If
that handler calls `.remove()` on the element, the data is cleared,
leaving private data undefined. We're reading a property from that
data so we need to guard against this.

Fixes jquerygh-4417
@mgol
Copy link
Member

mgol commented Oct 9, 2020

PR: #4799

mgol added a commit that referenced this issue Oct 19, 2020
In Chrome, if an element having a `focusout` handler is blurred by
clicking outside of it, it invokes the handler synchronously. If
that handler calls `.remove()` on the element, the data is cleared,
leaving private data undefined. We're reading a property from that
data so we need to guard against this.

Fixes gh-4417
Closes gh-4799
mgol added a commit that referenced this issue Oct 19, 2020
In Chrome, if an element having a `focusout` handler is blurred by
clicking outside of it, it invokes the handler synchronously. If
that handler calls `.remove()` on the element, the data is cleared,
leaving private data undefined. We're reading a property from that
data so we need to guard against this.

Fixes gh-4417
Closes gh-4799

(cherry picked from commit 5c2d087)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

5 participants