Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger click event: addEventListener is not triggered

I'm wondering why a addEventListener("click", function(){}) is not called when triggered by a jQuery .trigger("click") but it IS called when triggered by a dispatchEvent(new Event("click")).

var el = document.getElementById("foo");

$(el).click(function() { console.log("jquery click"); });
el.onclick = function() { console.log("onclick"); };
el.addEventListener("click", function() { console.log("addEventlistener click"); });

$(el).trigger("click");
console.log("--------");
el.dispatchEvent(new Event("click"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#foo" id="foo">foo</a>

This produces the following console output

(index):54 jquery click
(index):55 onclick
(index):59 --------
(index):54 jquery click
(index):55 onclick
(index):56 addEventlistener click

Am I missing something? Does jQuery "fake" a click by calling it's event listeners directly?

like image 830
23tux Avatar asked Nov 28 '17 15:11

23tux


1 Answers

jQuery's trigger fires the jQuery handlers and calls the .event() function on the element* — unless it's a click on an a element, in which case it doesn't do that second part. (It also treats checkboxes specially.) E.g., we see it if we use a div in your example:

var el = document.getElementById("foo");

$(el).click(function() { console.log("jquery click"); });
el.onclick = function() { console.log("onclick"); };
el.addEventListener("click", function() { console.log("addEventlistener click"); });

$(el).trigger("click");
console.log("--------");
el.dispatchEvent(new Event("click"));
<div id="foo"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

...but not on your a:

var el = document.getElementById("foo");

$(el).click(function() { console.log("jquery click"); });
el.onclick = function() { console.log("onclick"); };
el.addEventListener("click", function() { console.log("addEventlistener click"); });

$(el).trigger("click");
console.log("--------");
el.dispatchEvent(new Event("click"));
<a href="#foo" id="foo">foo</a>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

Why not? For "cross-browser consistency" the source says: See https://github.com/jquery/jquery/blob/master/src/event.js#L476 (that link is to a line number, and so may will rot):

    click: {

        // For checkbox, fire native event so checked state will be right
        trigger: function() {
            if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) {
                this.click();
                return false;
            }
        },

        // For cross-browser consistency, don't fire native .click() on links
        _default: function( event ) {
            return nodeName( event.target, "a" );
        }
    },

Note that bit at the end.


* This is a bit tricky to find. trigger says:

Any event handlers attached with .on() or one of its shortcut methods are triggered when the corresponding event occurs. They can be fired manually, however, with the .trigger() method.

...but triggerHandler says:

The behavior of this method is similar to .trigger(), with the following exceptions:

  • The .triggerHandler( "event" ) method will not call .event() on the element it is triggered on. This means .triggerHandler( "submit" ) on a form will not call .submit() on the form.
  • While .trigger() will operate on all elements matched by the jQuery object, .triggerHandler() only affects the first matched element.
  • Events triggered with .triggerHandler() do not bubble up the DOM hierarchy; if they are not handled by the target element directly, they do nothing.
  • Instead of returning the jQuery object (to allow chaining), .triggerHandler() returns whatever value was returned by the last handler it caused to be executed. If no handlers are triggered, it returns undefined

Could definitely be clearer on this point.

like image 187
T.J. Crowder Avatar answered Oct 15 '22 09:10

T.J. Crowder