Domanda

Click an element using triggerHandler() works:

$element = $('#gwt-debug-location-pill-edit-div:visible');
$element.triggerHandler('click');

But, clicking it using trigger(), doesn't:

$element.trigger('click');

Why is that?


To replicate this (in Firefox and Chrome):

  • Go to https://adwords.google.com/select/home, and log in using your credentials
  • Tools and Analysis -> Keyword Planner
  • Expand "Enter or upload keywords to see how they perform"
  • Using browser's console, try to click on the locations box (marked in red in the screenshot below) via the two methods above (you'll need to inject jQuery into the page. I used jQuerify to do that.)

enter image description here

È stato utile?

Soluzione

Let's compare jQuery.fn.trigger and jQuery.fn.triggerHandler:

trigger: function( type, data ) {
    return this.each(function() {
        jQuery.event.trigger( type, data, this );
    });
},
triggerHandler: function( type, data ) {
    var elem = this[0];
    if ( elem ) {
        return jQuery.event.trigger( type, data, elem, true );
    }
}

The only real difference is the fourth argument, true, given to jQuery.event.trigger with triggerHandler.

Looking at jQuery.event.trigger, the argument is called onlyHandlers, and among other things, the documentation of triggerHandler notes that:

  • The .triggerHandler() method does not cause the default behavior of an event to occur (such as a form submission).

We can see where the default behaviour is actually triggered:

// If nobody prevented the default action, do it now
if ( !onlyHandlers && !event.isDefaultPrevented() ) {

In the case that onlyHandlers is false (trigger()), and no event handler stopped the default event from executing, the default action will then be executed.

With onlyHandlers being true (triggerHandler()), this will never happen.

So, for the trigger() case, it ends up executing click() on the target element, which triggers the state change correctly—but it turns out that, in both the trigger() and triggerHandler() cases, the click was already correctly fired up in the loop through the eventPath above:

// Native handler
handle = ontype && cur[ ontype ];
if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {

So trigger('click') ends up clicking the element twice (!) — presumably because click() doesn't return false, so the event default action is never prevented — whereas triggerHandler('click') only does it once.

This can be verified by stepping through the jQuery.event.trigger method with the inspector and seeing the selector open, then close again.

The question is if this what we should generally expect; it seems strange that an otherwise-working event trigger would cause double triggers in the case of a DOM-only reaction.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top