When JavaScript fires an event, like click
, it doesn't just fire it on the event target (i.e. the thing that was clicked).
It also fires the event on every ancestor element. This means that an event listener on an ancestor can handle clicks on any of
its children.
The code below demonstrates this with a list, where we want to react to the user clicking any list item, and we want our reaction
to take into account which list item they clicked. We use a listener on the entire list, and just check e.target
to see what
list item was clicked.
The e.target
value is whatever element was clicked on directly. You would expect this to be a list item; however, it could also
be a child or descendant element of any list item. One of our list items has italicized text using the <em>
tag; if the user
clicks directly on that italicized text, then the EM
element will be the event target. For that reason, we actually want to use
e.target.closest("li")
.
That isn't perfect, however. If something that isn't an LI
element gets added to our list, then there are two ways that that
can fail:
-
If the user clicks on the non-
LI
child of the list, thene.target.closest("li")
will benull
, because the element that the user clicked on won't be inside of a list item... -
...unless the entire list is inside of an
LI
, in which casee.target.closest("li")
will be thatLI
outside of the list.
If we want to be paranoid, we can handle both of these cases: make sure that e.target.closest("li")
isn't null
, and make
sure that it's actually inside of our list (via Element.prototype.contains
).