W3docs

JavaScript - Dispatching di eventi personalizzati

Crea e invia eventi personalizzati in JavaScript con CustomEvent e dispatchEvent, passa dati tramite detail e disaccoppia i componenti.

Dispatching di eventi personalizzati in JavaScript

Il browser genera automaticamente eventi nativi come click, submit e keydown. Ma JavaScript ti consente anche di creare e lanciare i tuoi eventi personalizzati su qualsiasi nodo del DOM, per poi ascoltarli con lo stesso addEventListener() che già utilizzi per gli eventi nativi.

Questa è la base del design applicativo a basso accoppiamento: una parte del codice annuncia che qualcosa è successo ("dati caricati", "carrello aggiornato") senza sapere né preoccuparsi di chi stia ascoltando. Questa pagina illustra come creare eventi personalizzati con il costruttore CustomEvent, allegare dati ad essi, inviarli con dispatchEvent() e gestire gli errori più comuni.

Creare un evento personalizzato

Utilizza il costruttore CustomEvent. Il primo argomento è il tipo di evento (il nome che utilizzerai successivamente per ascoltarlo); il secondo è un object di opzioni:

let event = new CustomEvent("myEvent", {
  detail: { message: "This is a custom event!" },
  bubbles: true,
  cancelable: true
});

Le tre opzioni più utilizzate sono:

  • detail — qualsiasi valore (object, string, numero) che vuoi allegare all'evento. Il listener lo legge come event.detail. Questo è il canale dedicato ai dati personalizzati; le proprietà degli eventi nativi sono di sola lettura.
  • bubbles — quando è true, l'evento risale attraverso gli elementi antenati dopo l'attivazione, così un listener su un elemento padre (o su document) può intercettarlo. Il valore predefinito è false.
  • cancelable — quando è true, un listener può chiamare event.preventDefault() per segnalare che l'azione predefinita deve essere saltata. Il valore predefinito è false.

CustomEvent vs. Event

Esiste anche un costruttore Event semplice, ma non può trasportare dati — non ha detail. Usa sempre CustomEvent quando hai bisogno di passare informazioni insieme all'evento:

// No way to attach data here:
let bare = new Event("ping", { bubbles: true });

// Use CustomEvent to send a payload:
let withData = new CustomEvent("ping", {
  bubbles: true,
  detail: { at: Date.now() }
});

Inviare l'evento

Un evento creato non fa nulla finché non lo lanci su un elemento con dispatchEvent():

let target = document.getElementById("box");
target.dispatchEvent(event);

Ci sono due cose importanti da sapere su dispatchEvent():

  1. Viene eseguito in modo sincrono — a differenza di setTimeout, i listener vengono eseguiti immediatamente, prima che la riga successiva a dispatchEvent() venga eseguita.
  2. Restituisce un boolean: false se l'evento era cancelable e un listener ha chiamato preventDefault(), altrimenti true. Questo consente al codice che ha inviato l'evento di reagire a un "veto":
let cancelled = !target.dispatchEvent(event);
if (cancelled) {
  console.log("A listener prevented the default action.");
}

Puoi inviare l'evento su qualsiasi elemento. Inviarlo su document funziona perché gli eventi con bubbling lo raggiungono, ma lanciarlo sull'elemento specifico che "possiede" l'evento (e lasciarlo risalire) mantiene i tuoi listener circoscritti ed evita handler globali accidentali.

Ascoltare un evento personalizzato

Non esiste un'API speciale dal lato dell'ascolto — addEventListener() funziona esattamente come per click. I dati arrivano in event.detail:

element.addEventListener("myEvent", function (event) {
  console.log(event.detail.message); // "This is a custom event!"
});

Esempi pratici

Esempio 1: Comunicazione tra componenti

Supponiamo che due parti indipendenti di una pagina debbano comunicare senza avere riferimenti diretti l'una all'altra. Una invia un evento personalizzato; l'altra lo ascolta. Poiché l'evento ha bubbles, il listener può essere posizionato su document:

<button id="sender">Send Message</button>
// Listener in another component
document.addEventListener('componentMessage', function(event) {
  alert('Received message: ' + event.detail.message);
});

document.getElementById('sender').addEventListener('click', function() {
  // Create and dispatch the custom event
  let customEvent = new CustomEvent('componentMessage', {
    detail: { message: 'Hello from another component!' },
    bubbles: true,
    cancelable: true
  });
  document.dispatchEvent(customEvent);
});

Come funziona:

  • Facendo clic sul pulsante si crea e si invia un evento componentMessage che trasporta un messaggio in detail.
  • Un listener altrove intercetta l'evento e vi reagisce. Nessuno dei due lati importa l'altro — il nome dell'evento è l'unico contratto.

Esempio 2: Aggiornare l'interfaccia utente dopo una modifica ai dati

Gli eventi personalizzati ti consentono di separare la logica dei dati dalla logica di rendering. Il livello dati annuncia dataUpdated; il livello UI ascolta e ri-renderizza. Qui l'aggiornamento viene attivato dopo un breve ritardo per simulare un fetch asincrono:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Event UI Update Example</title>
</head>
<body>
<h1>User Status</h1>
<div id="userInfo">Loading user information...</div>

<script>
  // Function to simulate a data update
  function updateData() {
    let dataUpdateEvent = new CustomEvent('dataUpdated', {
      detail: { data: { username: 'user123', status: 'active' } }
    });
    document.dispatchEvent(dataUpdateEvent);
  }

  // UI component listening for data updates
  document.addEventListener('dataUpdated', function(event) {
    let userData = event.detail.data;
    document.getElementById('userInfo').innerHTML =
      `Username: <strong>${userData.username}</strong>, Status: <strong>${userData.status}</strong>`;
  });

  // Trigger the update after 2 seconds
  setTimeout(updateData, 2000);
</script>
</body>
</html>

Come funziona:

  • Dopo due secondi, updateData() invia un evento dataUpdated con i nuovi dati in detail.
  • Il listener dell'interfaccia utente legge event.detail.data e aggiorna la pagina. La funzione che ha prodotto i dati non tocca mai direttamente il DOM.

Annullare un evento personalizzato

Quando un evento è cancelable, un listener può chiamare preventDefault(). Il dispatcher vede quindi un valore di ritorno false da dispatchEvent() e può ignorare il suo comportamento predefinito — lo stesso schema che il browser usa per l'invio di form o i clic sui link. Questo snippet viene eseguito in Node e dimostra il flusso sincrono:

let target = new EventTarget();

target.addEventListener("save", (event) => {
  // Veto the save
  event.preventDefault();
});

let event = new CustomEvent("save", { cancelable: true });
let notCancelled = target.dispatchEvent(event);

console.log(notCancelled);          // false
console.log(event.defaultPrevented); // true

EventTarget è l'interfaccia base da cui ereditano i nodi del DOM, quindi la stessa logica si applica sia che tu esegua il dispatch su un elemento nel browser sia su un EventTarget standalone.

Conclusione

Gli eventi personalizzati ti offrono un modo pulito e senza framework per collegare le parti di un'applicazione. Creali con CustomEvent, allega un payload tramite detail, lancialo con dispatchEvent() e ascoltalo con il familiare addEventListener(). Imposta bubbles: true quando un elemento padre deve intercettare l'evento, e cancelable: true quando il dispatcher deve rispettare il veto di un listener. Il risultato è un codice in cui i moduli comunicano tramite eventi denominati anziché riferimenti diretti — più facile da testare, estendere e mantenere.

Per approfondire, scopri come gli eventi si propagano nel DOM in bubbling e capturing, come i listener vengono collegati nella gestione degli eventi nel DOM, e come preventDefault() influisce sulle azioni predefinite del browser.

Esercitazione

Pratica
Quali affermazioni sugli eventi personalizzati in JavaScript sono corrette?
Quali affermazioni sugli eventi personalizzati in JavaScript sono corrette?
Was this page helpful?