Skip to content

Chaining .on() broken for null handlers in jQuery 2.2.0 (inconsistency with 1.12.0) #2812

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

Closed
dwilson6 opened this issue Jan 11, 2016 · 16 comments
Labels
Milestone

Comments

@dwilson6
Copy link
Contributor

It looks like a bug was introduced in jquery 2.2.0 with the 'on' function.

If you have code that registers a bunch of handlers in a chain and one of the callbacks is null, the on function will return the window object when the callback is null which causes the chaining to fail. This works with jquery 2.1.4. After a little investigation, it looks like the 'on' method was refactored to be global within jquery's scope and returns this (which used to be the jquery object but now is window).

//example from jquery impromptu plugin
$('.selector').on("keydown",keyDownEventHandler)
.on('impromptu:loaded', opts.loaded)
.on('impromptu:close', opts.close)
.on('impromptu:statechanging', opts.statechanging)
.on('impromptu:statechanged', opts.statechanged);

@dmethvin
Copy link
Member

A callback can't be null, it's not a documented input. Previously that silently did nothing but it seems like that makes it harder to find the bug causing a null input.

@mgol
Copy link
Member

mgol commented Jan 11, 2016

It's weird, though, we brought the check for null back in 2.2.0, there's a test for the click event:
https://github.com/jquery/jquery/blob/2.2.0/test/unit/event.js#L8-L21.

EDIT: Ah, I misread the report. It's not throwing but returns window instead of the original element.

@dwilson6
Copy link
Contributor Author

Correct. The callback doesn't necessarily have to be null but if its not a function, window is returned

@dwilson6
Copy link
Contributor Author

After looking more at the source code, it seems like this reverted commit is the culprit (the on function was broken out so 'this' has a different meaning now): 3cc496c

@mgol
Copy link
Member

mgol commented Jan 11, 2016

A function or false which is treated specially. As @dmethvin mentioned, this is not a supported input so we can technically do what we want here but I'd like to see what's really happening here. I don't immediately see why the this leaks the global object since the functions in which it appears are supposed to be bound to the proper elements.

Thanks for the report!

@mgol mgol self-assigned this Jan 11, 2016
@mgol
Copy link
Member

mgol commented Jan 11, 2016

@dwilson6

After looking more at the source code, it seems like this reverted commit is the culprit (the on function was broken out so 'this' has a different meaning now): 3cc496c

Good point, that's it!

Note that we've removed this check on master, using .on(event, null) will throw in jQuery 3.0.0. We've only restored it here so that both 1.12.0 & 2.2.0 don't throw (so that they're consistent even though this is unsupported input)... but the fix is buggy as it seems.

I'd fix it on the 2.2-stable branch but this doesn't seem important enough to warrant a 2.2.1 release so unless we find something important to patch this will most likely stay as it is.

Thoughts, @jquery/core?

@dmethvin
Copy link
Member

The code had been refactored as a non-method function to hide the private one arg, that's when this changed meanings. I don't think this is critical enough to force an immediate 2.2.1 either, especially since it's not documented.

If we have a unit test in there it seems like we're saying we want a non-false but falsy handler to be a chainable no-op. I really dislike that kind of behavior because it lets mistakes happen a lot easier, but we should decide what we want to do and make sure we're testing and documenting it right.

@mgol mgol removed their assignment Jan 11, 2016
@herbalite
Copy link

The issue I encountered is somewhat similar to this here, as it relates to the event refactoring. If you think this warrants it's own feature/bug report that is fine with me.

Here's what happened:

After upgrading to jQuery 2.2.0 hoverintent for ui-tabs threw an error e.preventDefault() is not a function in the user defined event handler callback function, even though a quick test showed that typeof e.preventDefault returned 'function'.

The code I was using is an updated version of this http://stackoverflow.com/questions/15346939/adding-hoverintent-to-jquery-ui-tabs.

The most important change from that code is the line

jQuery.event.handle.apply( that, args );
jQuery.event.dispatch.apply( that, args );

And i had changed from bind()/unbind() to on()/off(). I reverted to bind()/unbind() during bug triaging, but that made no difference to the error.

After unsuccessfully trying to pin point the problem I found this jquery-ui example

http://jqueryui.com/accordion/#hoverintent

Using that code my ui-tabs with hoverintent and hoverintent in general works again, although I did made some refactoring (using on()/off() instead of bind()/unbind(), and giving the events a namespace).

Since this issue shows up when using special event handlers, it might have an effect on other plug-ins, I hope this report helps to save people from spending a lot of time to fix similar issues.

Probably needs no fixing in jQuery, altough the fixed version is less performant than using jQuery.event.dispatch directly as it doesn't have to do all the work that is done in the trigger function (which seems to be a special event in itself)

@dwilson6
Copy link
Contributor Author

Yeah, I agree that its probably not critical enough for a quick 2.2.1 release. It could potentially break plugins that chain on like the one above where not all options are always set though so it might be worth fixing for compatibility. Though plugins shouldn't be doing that anyways.

@mgol
Copy link
Member

mgol commented Jan 13, 2016

@dwilson6 Would you like to submit a patch against the 2.2-stable branch? Judging by #2822 we might need to release 1.12.1/2.2.1 anyway so this is a good candidate to make the branches consistent again.

@mgol mgol changed the title Jquery 2.2.0 'on' function has a bug when chaining with an null callback function Chaining .on() broken for null handlers in jQuery 2.2.0 (inconsistency with 1.12.0) Jan 13, 2016
@mgol mgol added this to the 1.12.1/2.2.1 milestone Jan 13, 2016
@mgol mgol added the Event label Jan 13, 2016
@mgol
Copy link
Member

mgol commented Jan 13, 2016

I've added a milestone.

@dwilson6
Copy link
Contributor Author

Yeah, I will do that

@timmywil
Copy link
Member

Fixed by #2825

@vankampenp
Copy link

@timmywil
Copy link
Member

@vankampenp If it's related to this issue, it has already been fixed and will be released in 2.2.1.

@Gemorroj
Copy link

Not work fine, see jquery-archive/jquery-mobile#8381 (comment)

@lock lock bot locked as resolved and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests

7 participants