Adactio: Journal—event.target.closest

By admin

Eric
PERSON

mentioned the

JavaScript
ORG

closest method. I use it all the time.

When I wrote the book

DOM Scripting
PERSON

back in

2005
DATE

, I’d estimate that

90%
PERCENT

of the JavaScript I was writing boiled down to:

Find these particular elements in the

DOM
ORG

and When the user clicks on

one
CARDINAL

of them, do something.

It wasn’t just me either. I reckon that was

90%
PERCENT

of most JavaScript on the web: progressive disclosure widgets, accordions, carousels, and so on.

That’s one of the reasons why jQuery became so popular. That

first
ORDINAL

step (“find these particular elements in the

DOM
ORG

”) used to be a finicky affair involving getElementsByTagName , getElementById , and other long-winded

DOM
ORG

methods. jQuery came along and allowed us to use

CSS
ORG

selectors.


These days
DATE

, we don’t need jQuery for that because we’ve got querySelector and querySelectorAll (and we can thank jQuery for their existence).

Let’s say you want to add some behaviour to every button element with a class of special . Or maybe you use a data- attribute instead of the class attribute; the same principle applies. You want something special to happen when the user clicks on

one
CARDINAL

of those buttons.

Use querySelectorAll(‘button.special’) to get a list of all the right elements, Loop through the list, and Attach

addEventListener(‘click
PERSON

‘) to each element.

That’s fine for a while. But if you’ve got a lot of special buttons, you’ve now got a lot of event listeners. You might be asking the browser to do a lot of work.

There’s another complication. The code you’ve written runs once, when the page loads. Suppose the contents of the page have changed in the meantime. Maybe elements are swapped in and out using

Ajax
ORG

. If a new special button shows up on the page, it won’t have an event handler attached to it.

You can switch things around. Instead of adding lots of event handlers to lots of elements, you can add

one
CARDINAL

event handler to the root element. Then figure out whether the element that just got clicked is special or not.

That’s where closest comes in. It makes this kind of event handling pretty straightforward.

To start with, attach the event listener to the document:

document.addEventListener(‘click’, doSomethingSpecial, false);

That function doSomethingSpecial will be executed whenever the user clicks on anything. Meanwhile, if the contents of the document are updated via

Ajax
ORG

, no problem!

Use the closest method in combination with the target property of the event to figure out whether that click was something you’re interested in:

function doSomethingSpecial(event) { if (event.target.closest(‘button.special’)) { // do something } }

There you go. Like querySelectorAll , the closest method takes a CSS selector—thanks again, jQuery!

Oh, and if you want to reduce the nesting inside that function, you can reverse the logic and return early like this:

function doSomethingSpecial(event) { if (!event.target.closest(‘button.special’)) return; // do something }

There’s a similar method to closest called matches . But that will only work if the user clicks directly on the element you’re interested in. If the element is nested within other elements, matches might not work, but closest will.

Like

Eric
PERSON

said: