2

In jQuery we are used to binding click handlers like this:

$(".all-buttons").click(function() {
    var btn = this;
    console.log(btn.innerHTML);
});

I would like to be able to use the same functionality with ES6 arrow functions like this:

$(".all-buttons").click(btn => console.log(btn.innerHTML));

The issue is that jQuery doesn't pass the current element as an argument like other native javascript functions do, for example Array.forEach()

Another issue is that arrow functions cannot be "applied" i.e. called like fn.apply(this, args), which is what jQuery relies on for letting me know which element triggered the event.

I just put the "click" example here, but I would like to be able to apply this to any jQuery callback.

Does anybody have any suggestions about how to achieve this? perhaps to use a different library that does call my callbacks with the element as an argument? or perhaps a jquery plugin? or a javascript trick I don't know about?

I appreciate the help.

santiago arizti
  • 4,175
  • 3
  • 37
  • 50

2 Answers2

16

The basic functionality is trivial: The Event object the handler receives has a currentTarget property which is the same as this:

$(".all-buttons").click(e => console.log(e.currentTarget.innerHTML));

Note this is not the same as e.target:

  • target is the element the event is targeted at, whereas
  • currentTarget is the element the event is passing through on en route to that target on which this handler was hooked

So for instance, if you have

<div>
    <span>click me</span>
</div>

...and you have a handler hooked to that div, clicking the span will give you e.target = the span, e.currentTarget = the div.

Regarding "other libraries," library recommendations are off-topic for SO. But I'll note that on modern browsers:

  • The NodeList returned by the DOM's own querySelectorAll has forEach, which makes it easy to loop over matches (it's also trivial to polyfill on any vaguely-recent browser)
  • DOM elements also now have a closest method which makes event delegation with the DOM much simpler than it used to be (and again, can be polyfilled).
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • thanks, I figured this out not much later than posting the question, your answer is better though. – santiago arizti Feb 22 '18 at 17:40
  • will this work $(".all-buttons").click(() => console.log(this.innerHTML)); @T.J. Crowder – Punith Jain Feb 22 '18 at 17:43
  • @PunithJain: Only if you want the `innerHTML` of whatever `this` is where that code appears (**not** of the clicked element, since arrow functions close over `this` instead of having their own). – T.J. Crowder Feb 22 '18 at 17:44
  • Logan's probably right about the dupetarget. I was thinking the other aspects of the question made it its own thing, but... – T.J. Crowder Feb 22 '18 at 17:46
1

Ok, after some digging around in the event argument passed by jQuery, I see that this is available:

$(".all-buttons").click(event => console.log(event.target.innerHTML));

Where event.target is the clicked button.

I don't know much about event bubbling and if the element that jQuery passes as this is always the same as event.target though.

santiago arizti
  • 4,175
  • 3
  • 37
  • 50
  • 1
    `target` is not the correct property, it's frequently not the same as `this` in jQuery callbacks. See my answer for details. – T.J. Crowder Feb 22 '18 at 17:38