Criando Eventos Personalizados em JavaScript
A capacidade de disparar eventos programaticamente abre o caminho para a criação de eventos personalizados. Isso permite definir e disparar eventos arbitrários.
Por exemplo, temos a função construtora Account
, que aceita uma quantia de dinheiro e cria uma conta monetária condicional:
function Account(money) {
_money = money;
this.pay = function (sum) {
if (_money >= sum) {
_money -= sum;
console.log(_money);
}
};
}
A variável _money
armazena a quantia de dinheiro atual na conta. Usamos a função pay
para gastar uma certa quantia, se o saldo permitir. Suponha que precisamos notificar o sistema quando ocorrer um débito da conta. Poderíamos fazer isso diretamente no método pay
usando console.log()
para mostrar algum texto. Mas, no momento de escrever esse código, pode não ser claro qual texto exato deve ser exibido, ou talvez a notificação não deva aparecer no console, mas sim em uma janela do navegador ou ser enviada a um recurso de rede específico. A função construtora pode ser usada em Node.js, onde pode ser necessária uma abordagem diferente. Outros desenvolvedores que usarem nossa função podem ter suas próprias ideias sobre o que fazer quando os fundos são debitados. De qualquer forma, o principal é notificar o sistema que um débito ocorreu, e definir eventos personalizados pode ajudar a abordar todas essas situações.
Para definir eventos personalizados, podemos usar o construtor Event
, ao qual passamos o nome do evento. Considere o seguinte programa:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Programício</title>
</head>
<body>
<button id="btn">Pay</button>
<script>
const button = document.getElementById("btn");
const myAcc = new Account(100); // conta monetária condicional
// definindo um manipulador de eventos para todo o documento
document.addEventListener("payment", () => console.log("Payment succeeded!"));
// ao clicar no botão, executamos o método pay
button.addEventListener("click", () => myAcc.pay(50));
function Account(money) {
_money = money;
this.pay = function (sum) {
if (_money >= sum) {
_money -= sum;
console.log(_money);
const event = new Event("payment"); // definindo o objeto de evento
document.dispatchEvent(event); // disparando o evento para todo o documento
}
};
}
</script>
</body>
</html>
Criamos um objeto Event
que representa o evento "payment" e depois disparamos esse evento.
Para manipular esse evento, nos inscrevemos nele:
document.addEventListener("payment", () => console.log("Payment succeeded!"));
A inscrição no evento é feita para todo o documento. O manipulador de eventos simplesmente exibe uma linha no console.
Ao pressionar o botão, chamamos o método pay
do objeto myAcc
e assim disparamos o evento "payment" (se houver fundos suficientes).
Para um teste mais robusto, pressionamos o botão:
Também podemos obter um objeto de evento no manipulador:
document.addEventListener("payment", (e) => {
console.log(e.type); // payment
console.log("Payment succeeded!");
});
CustomEvent
Embora possamos usar o tipo Event
para definir eventos personalizados, ele não é ideal se quisermos passar informações adicionais para o manipulador de eventos, como a quantia debitada ou o saldo atual. Para esses casos, é melhor usar o tipo CustomEvent
. Vamos modificar o código JavaScript da seguinte maneira:
const button = document.getElementById("btn");
document.addEventListener("payment", (e) => {
console.log("Payment succeeded!");
console.log("Payment Sum:", e.detail.paymentSum); // obtendo dados do evento
console.log("Current balance:", e.detail.balance);
});
const myAcc = new Account(100);
// ao clicar no botão, executamos o método pay
button.addEventListener("click", () => myAcc.pay(50));
function Account(money) {
_money = money;
this.pay = function (sum) {
if (_money >= sum) {
_money -= sum;
const event = new CustomEvent("payment", {
detail: {
// passando dados sobre o evento em CustomEvent
paymentSum: sum,
balance: _money,
},
});
document.dispatchEvent(event); // disparando o evento para todo o documento
}
};
}
No CustomEvent
, passamos um objeto de configuração como segundo parâmetro, que possui a propriedade detail
. Esta propriedade representa um objeto com um conjunto arbitrário de propriedades. Neste caso, definimos as propriedades paymentSum
e balance
e passamos os valores de interesse:
const event = new CustomEvent("payment", {
detail: {
paymentSum: sum,
balance: _money,
},
});
Disparamos o evento CustomEvent
da mesma maneira que o evento Event
.
Ao processar o evento, podemos obter os dados transmitidos através da propriedade detail
:
document.addEventListener("payment", (e) => {
console.log("Payment succeeded!");
console.log("Payment Sum:", e.detail.paymentSum); // obtendo dados do evento
console.log("Current balance:", e.detail.balance);
});
Exemplo de saída no console após o primeiro clique no botão:
Payment succeeded! Payment Sum: 50 Current balance: 50
Dessa maneira, podemos definir e gerenciar outros eventos também. Por exemplo, podemos definir outro evento caso não haja fundos suficientes para o pagamento:
const button = document.getElementById("btn");
document.addEventListener("payment_success", (e) => {
console.log("Payment succeeded!");
console.log("Payment Sum:", e.detail.paymentSum);
console.log("Current balance:", e.detail.balance);
});
document.addEventListener("payment_fail", (e) => {
console.error("Payment failed");
console.error("Current balance:", e.detail.balance, "Requested Sum: ", e.detail.paymentSum);
});
const myAcc = new Account(100);
button.addEventListener("click", () => myAcc.pay(50));
function Account(money) {
_money = money;
this.pay = function (sum) {
const data = {
paymentSum: sum,
balance: _money,
};
if (_money >= sum) {
_money -= sum;
const event = new CustomEvent("payment_success", {
detail: data,
});
document.dispatchEvent(event);
} else {
const event = new CustomEvent("payment_fail", {
detail: data,
});
document.dispatchEvent(event);
}
};
}
Agora, se houver fundos suficientes na conta, o evento "payment_success" é disparado; se não houver, o evento "payment_fail" é disparado. Para cada um desses eventos, definimos um manipulador próprio.
Saída do console do programa (após três cliques no botão):
Payment succeeded! Payment Sum: 50 Current balance: 100 Payment succeeded! Payment Sum: 50 Current balance: 50 Payment failed Current balance: 0 Requested Sum: 50