Skip to main content

Bug Tracker

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 Danack@basereality.com comment:1

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.

Changed February 24, 2013 09:08PM UTC by dmethvin comment:2

owner: → Danack@basereality.com
status: newpending

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 Danack@basereality.com comment:3

status: pendingnew
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 scottgonzalez 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 dmethvin comment:5

resolution: → wontfix
status: newclosed

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 triggerHandlers 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.