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

Event handlers are not triggered across multiple instances #4815

Closed
torotil opened this issue Dec 1, 2020 · 8 comments
Closed

Event handlers are not triggered across multiple instances #4815

torotil opened this issue Dec 1, 2020 · 8 comments

Comments

@torotil
Copy link

torotil commented Dec 1, 2020

Description

When I have multiple jQuery instances on the same page. Events triggered using $.trigger() with one instance don’t execute event handlers bound with $.on() using another instance.

Link to test case

https://jsbin.com/dawajojave/edit?html,js,output

In the test case there is a select. Two versions of jQuery are injected. Each of them binds to $('select').on('change') and updates the value in the first list. In the second list there is a button triggering a change in the select value using $('select').val('grapes').trigger('change') for each version.

Expected result

Both values in the first list are changed regardless of how the change was made to the select.

Actual result

While both jQuery instances get notified about changes to the select when it’s used directly they only get the change event from ”their own” buttons.

@mgol
Copy link
Member

mgol commented Dec 1, 2020

Thanks for the report. jQuery doesn't rely on the dispatchEvent API for multiple reasons, one of them being that jQuery trigger calls native behavior in addition to executing event handlers while dispatchEvent just calls the handlers in most cases. trigger relies on its internal record of attached jQuery handlers so it cannot work with a different jQuery instance - version doesn't matter, you may have used the same one and the behavior would be the same.

Changing that would be a huge task that we'd most likely fail. We do plan an event subsystem refactor in 4.0 - see https://github.com/jquery/jquery/wiki/jQuery-4.0-Event-Design for some ideas - but I don't think we'll manage to change this part.

@mgol mgol closed this as completed Dec 1, 2020
@torotil
Copy link
Author

torotil commented Dec 2, 2020

Thanks for taking the time to look at this. Although a “wontfix” is not the answer I hoped for it is great to have one so quickly.

So this means essentially: While it’s possible to use multiple instances of jQuery on the same page. Scripts using different versions can’t interact using jQuery’s event subsystem.

From my PoV this makes having multiple instances of jQuery useless except for the most simple cases. Seems that we have to find a way around that somehow. 🤔

Maybe it would be good to mentioned that (rather prominently) in the docs about $.noConflict(), $.on() and $.trigger(). Should I post another issue about that or is it better to reuse this one?

@mgol
Copy link
Member

mgol commented Dec 2, 2020

From my PoV this makes having multiple instances of jQuery useless except for the most simple cases. Seems that we have to find a way around that somehow. 🤔

This doesn't just affect jQuery, native handlers will also not be called on jQuery trigger calls. Support for mixing multiple jQuery versions is mostly useful in composed pages that may each include jQuery separately so that they don't conflict with each other. It's not meant to interact like that between themselves.

As for documentation, please open an issue on https://github.com/jquery/api.jquery.com, ideally also prepare a PR with your proposed wording. All doc pages for jQuery APIs are in the entries directory.

@dmethvin
Copy link
Member

dmethvin commented Dec 2, 2020

jQuery has had this behavior since its inception in 2006, and during that time I can only remember maybe five or so reports of people being confused about it or wanting the feature. As @mgol says, the intent of the noConflict feature is mostly intended to prevent different versions on the same page from interfering with one another, and letting different versions trigger each other's events would certainly seem like interference. Since the internal data structure and behavior of jQuery events have changed across versions, it's not even clear we could do it if we wanted to.

@torotil
Copy link
Author

torotil commented Dec 3, 2020

@dmethvin I’m not even sure I want this feature ;-) It was just unexpected. It was rather non-obvious and cost me quite some time to debug because of that.

My use case:

  • Multiple JavaScripts acting on the same form elements eg. one that prefills values and select2.
  • Part of the JavaScript uses the global scoped jQuery on a legacy site (Drupal7 upgraded from 1.3 to 1.8). The other part is built using Parcel using jQuery 3.5.1.
  • The symptom is that the value is prefilled into the select element, but select2 doesn’t update (because it doesn’t get the change event).

So having part of your JS being able to use modern jQuery while other parts are still legacy is not a use-case.

The compromise is likely to be to try and upgrade the legacy site to jQuery 2.2+ and downgrade the Parcel bundle accordingly to be able to use the global scoped jQuery.

@torotil
Copy link
Author

torotil commented Dec 3, 2020

To trigger handlers bound via jQuery without also triggering the native event, use .triggerHandler() instead.

There is this sentence in the docs about .trigger() that seems to imply that .trigger() does trigger the native event.

@mgol
Copy link
Member

mgol commented Dec 3, 2020

This just means that e.g. calling .trigger( "click" ) will also call the native .click() method on the element: https://github.com/jquery/jquery/blob/3.5.1/src/event/trigger.js#L150. However, that call is guarded by silencing jQuery handlers so that they're not fired twice as we propagate them by ourselves before that call; see: https://github.com/jquery/jquery/blob/3.5.1/src/event/trigger.js#L150 & https://github.com/jquery/jquery/blob/3.5.1/src/event.js#L160-L161.

@torotil
Copy link
Author

torotil commented Aug 25, 2021

I have now implemented a jQuery event bridge that makes sharing events across jQuery instances possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants