Side navigation
#13506 closed bug (wontfix)
Opened February 24, 2013 12:35PM UTC
Closed February 25, 2013 01:28PM UTC
stopPropagation behaviour when trigger is passed an event.
Reported by: | Danack@basereality.com | Owned by: | Danack@basereality.com |
---|---|---|---|
Priority: | undecided | Milestone: | None |
Component: | unfiled | Version: | 1.9.1 |
Keywords: | Cc: | ||
Blocked by: | Blocking: |
Description
The stopPropagation behaviour is very unexpected when passed an event object. I believe it works incorrectly whereas the behaviour is correct when passed an event name.
Pass an event Name - works as expected
function someFunction(event){ event.stopPropagation(); } $('#object1).on('customEvent', someFunction).addClass('customEventClass'); $('#object2).on('customEvent', someFunction).addClass('customEventClass'); $(".customEventClass").trigger('customEvent');
As expected both object1 and object2 will have the function 'someFunction' called, but the event won't bubble up the DOM tree.
Pass an event Name - very unexpected behaviour
function someFunction(event){ event.stopPropagation(); } $('#object1).on('customEvent', someFunction).addClass('customEventClass'); $('#object2).on('customEvent', someFunction).addClass('customEventClass'); var event = jQuery.Event('customEvent'); $(".customEventClass").trigger(event);
Only one of the objects will receive the event. I expected both of them to receive the event.
The problem appears to appear to lie in the code
"while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {"
in the function "trigger: function( event, data, elem, onlyHandlers )"
The event object is passed in to this function and so on to the callback function for the first object, which calls event.stopPropagation() on the object, which sets the prototypes function "isPropagationStopped" to "returnTrue"
On the second (and subsequent) calls to "trigger: function( event, data, elem, onlyHandlers )" the event object still has "isPropagationStopped" set to "returnTrue" and so it doesn't actually get triggered for the rest of the elements.
I think the stopPropagation behaviour should be the same for when trigger is passed an event object, as when it is passed a string.
Attachments (0)
Change History (5)
Changed February 24, 2013 12:44PM UTC by comment:1
Changed February 24, 2013 09:08PM UTC by comment:2
owner: | → Danack@basereality.com |
---|---|
status: | new → pending |
Your example is basically equivalent to this:
var event = jQuery.Event('customEvent'); $.each($(".customEventClass"), function() { $(this).trigger(event); });
See the problem? The event
is reused and propagation is stopped in the first iteration. I don't think it would appropriate for us to change the event between calls since other things may have changed. For example, why use the Event
in the first place? Are you passing additional data in the object that you need to preserve across triggering for each element?
Changed February 25, 2013 01:28AM UTC by comment:3
status: | pending → new |
---|
See the problem?
Yes, I can see the problem, and if that was what I'd written, I'd consider it to be a bug in my code. But that bit of functionality is in the jQuery library so I consider it a bug in that instead.
For example, why use the Event in the first place?
I was planning on extending the event object to be able to pass data back from the code that got triggered to the code that triggered the event like this:
http://jsfiddle.net/Danack/gWLy2/
I realise that there are other ways of achieving this, and yes I can see that trying to fix this might be incredibly messy as (as you say), you can't tell what else may have been modified in the event object. However:
1) stopPropagation is only meant to stop the event from bubbling up the DOM. It's not meant to stop the event from occurring at all on subsequent $.each() loops.
2) It really is a gotcha, as the behaviour is completely different from passing in a string event name, even though reading the documentation they should have the same behaviour.
Changed February 25, 2013 04:13AM UTC by comment:4
This is absolutely working as intended. If you provide an event object, then the purpose is to have control over the event and be able to inspect it after triggering. This is a fairly advanced use case and it's important to understand what you're doing if you're going to use it. There is nothing that should change here.
Changed February 25, 2013 01:28PM UTC by comment:5
resolution: | → wontfix |
---|---|
status: | new → closed |
In the example it seems that you're stopping propagation to avoid any bubbling, which indicates to me this is being used like a custom pub/sub and not for DOM-like events. You *can* do that but remember the model has been set up primarily to accommodate DOM conventions and not a general pub/sub message system.
Just have your own loop that triggerHandler
s each element; create a fresh Event
for each call and inspect it afterwards. Alternatively you could set a data property on the element that was a function and call that; it would be less overhead.
I added a fiddle:
http://jsfiddle.net/Danack/q3MJM/2/
I believe that the event callback should be called 4 times, but it is only called 3.