Bug Tracker

Opened 6 years ago

Closed 6 years ago

#13506 closed bug (wontfix)

stopPropagation behaviour when trigger is passed an event.

Reported by: Danack@… Owned by: Danack@…
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.

Change History (5)

comment:1 Changed 6 years ago by Danack@…

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.

comment:2 Changed 6 years ago by dmethvin

Owner: set to Danack@…
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?

comment:3 Changed 6 years ago by Danack@…

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.

comment:4 Changed 6 years ago by scottgonzalez

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.

comment:5 Changed 6 years ago by dmethvin

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.

Note: See TracTickets for help on using tickets.