event.target vs event.currentTarget: qual usar?
Tags: javascript, eventtarget, eventcurrenttarget, addeventlistener
Published: 2023-02-16 13:18:40

## É muito comum você conhecer o event.target mas ainda não ter ouvido falar no event.currentTarget. Entenda a diferença.
 
Se você conhece o `event.target`, é tentador usar ele em situações como essa.
 
Imagine que você tem um ecommerce, e essa é sua página de produto:
 
![página de produto de um ecommerce, à esquerda mostra a foto de destaque do produto que é uma roupa, e à direita 4 miniaturas com cores diferentes do produto](https://www.datocms-assets.com/64896/1676517785-ecommerce.jpg)
 
Nela, o usuário vê a imagem de destaque à esquerda, e as minuatura do produto à direita. E digamos que você queira mudar a imagem de destaque, a cada clique nas miniaturas. Para isso, é preciso descobrir em qual cor o usuário clicou.
 
Infelizmente, usar o `event.target` aqui pode causar alguns probleminhas.
 
Veja o que pode acontecer.
 
## O problema do event.target
 
Abaixo está a seção com as miniaturas das cores:
 
```html
<button class="color-button" data-color="blue">
  <img src="blue.png" />
</button>
<button class="color-button" data-color="gray">
  <img src="gray.png" />
</button>
<button class="color-button" data-color="red">
  <img src="red.png" />
</button>
<button class="color-button" data-color="green">
  <img src="green.png" />
</button>
```
 
Perceba que cada botão possui um atributo `data-color` com a sua cor. Isso será importante daqui a pouco.
 
Agora veja como fica o script para adicionar um evento de clique nesses botões:
 
```javascript
// Pegar os botões
const colorButtons = document.querySelectorAll('.color-button');

// Iterar por eles, e adicionar um evento
// que muda a foto principal com base na cor
colorButtons.forEach(function(button) {
  button.addEventListener('click', changePictureByColor);

// Criar a função do evento
function changePictureByColor(event) {
  // ...
}
```
 
Até aqui tudo bem.
 
Agora, na função `changePictureByColor` você precisa *descobrir qual foi a cor clicada*.
 
Já que a cor está no atributo `data-color` de cada botão, basta pegar o seu valor:
 
```javascript
function changePictureByColor(event) {
  const clickedColor = event.target.getAttribute('data-color');
  // ...
}
```
 
Agora com a variável `clickedColor` em mãos, você pode seguir com a função e trocar a imagem em destaque.
 
Certo? Errado!
 
A sua função começa a estourar erros e mais erros... E após muito suor, você descobre que a variável `clickedColor` retorna `null`. Mas como?!
 
## Como obter o elemento HTML alvo do evento
 
Console, eu escolho você!
 
Você então invoca uma chuva de `console.log` até descobrir que *`event.target` não aponta para o botão. E sim para a imagem dentro do botão*. E como a imagem não tem um atributo `data-color`, o caos começa.
 
Veja algumas formas de corrigir isso.
 
## Adicionar o atributo data-color na imagem
 
Essa é a solução que gosto menos.
 
```html
<button class="color-button">
  <img src="blue.png" data-color="blue" />
</button>
<button class="color-button">
  <img src="gray.png" data-color="gray" />
</button>
<button class="color-button">
  <img src="red.png" data-color="red" />
</button>
<button class="color-button">
  <img src="green.png" data-color="green" />
</button>
```
 
Isso porque, caso o usuário clique na pontinha do botão, ali onde a tag `<img>` já não existe mais, o `event.target` será o botão. E nesse caso, ele não possui o `data-color`.
 
Outra opção é...
 
## Adicionar o atributo data-color na imagem e no botão
 
Antes eu estava de brincadeira. ESSA SIM é a solução que gosto menos.
 
Alguns dos motivos são:
 
- O dado fica repetido em mais de um lugar
- Caso existam outros elementos dentro de `<button>`, todos eles precisariam do atributo.
 
Uma solução um pouco melhor (que usei por muito tempo) é...
 
## Usar o método closest() do Javascript
 
Voltarei com o HTML original, com o `data-color` no botão:
 
```html
<button class="color-button" data-color="blue">
  <img src="blue.png" />
</button>
<button class="color-button" data-color="gray">
  <img src="gray.png" />
</button>
<button class="color-button" data-color="red">
  <img src="red.png" />
</button>
<button class="color-button" data-color="green">
  <img src="green.png" />
</button>
```
 
Agora vou adicionar algumas linhas na função, para garantir que peguei o botão:
 
```javascript
function changePictureByColor(event) {
  const clickedButton = event.target.closest('.color-button'); // pegar botão
  const clickedColor = clickedButton.getAttribute('data-color'); // pegar cor
  // ...
}
```
 
O método `closest()` recebe um seletor e retorna o primeiro elemento que corresponda a esse seletor. Porém em vez de buscar na página inteira, o método sobe na árvore HTML.
 
Então quando executo `event.target.closest('.color-button')`, os passos que a função `closest()` executa são os seguintes:
 
1. `event.target` (a imagem) possui a classe `color-button`? Não, então executa novamente com o elemento pai da imagem
2. `<button class="color-button">` possui a classe `color-button`? Sim, então retorna ele
3. Fim
 
Caso chegue até o elemento raiz `<html>` e não encontre, retorna `null`.
 
Assim, tenho a certeza de que agora peguei o botão. Agora posso pegar a cor clicada e prosseguir.
 
Usei essa solução por muito tempo me achando o máximo. Até descobrir que posso...
 
## Usar event.currentTarget em vez de event.target
 
E só isso!
 
```javascript
function changePictureByColor(event) {
  const clickedColor = event.currentTarget.getAttribute('data-color');
  // ...
}
```
 
Assim, a variável `clickedColor` sempre vai receber a cor presente no atributo `data-color` do botão.
 
Mas que magia aconteceu aqui?
 
**O `event.target` aponta para o elemento que dispara o evento, ou seja, aquele que cliquei de fato. Isso pode ser o próprio botão, ou qualquer elemento dentro dele, como a imagem. Assim, em cada clique, `event.target` pode ser um elemento HTML diferente.**
 
**Já o `event.currentTarget` aponta sempre para o mesmo elemento. Aquele que foi atribuído ao `addEventListener`.**
 
No exemplo do ecommerce que você acabou de ver, `event.target` e `event.currentTarget` apontam para elementos diferentes.
 
## Callback
 
Como dito, a propriedade `event.target` aponta para o elemento que disparou o evento.
 
Já o `event.currentTarget` aponta para o elemento que possui o event listener associado a ele.
 
Fique atento para usar cada propriedade no momento certo.