Eventi nel DOM con addEventListener e delega: gestire i click sui modali in modo pulito

by Anastasia P.
SHARE
Eventi nel DOM con addEventListener e delega: gestire i click sui modali in modo pulito
© Guida-HTML5.it

Introduzione

Quando si lavora con il DOM, una delle situazioni più comuni è dover gestire i click su pulsanti o elementi interattivi dentro una finestra modale. Pensiamo a un modale con più azioni: chiudi, salva, annulla, elimina. Se ogni volta aggiungiamo un listener a ogni singolo bottone, il codice può diventare dispersivo e difficile da mantenere, soprattutto se il contenuto del modale cambia dinamicamente.

In questo tutorial vedremo un sotto-argomento molto pratico: come usare addEventListener e la delega degli eventi per gestire i click all’interno di un modale. Questo approccio è utile perché permette di centralizzare la logica, ridurre il numero di listener e semplificare la manutenzione del codice.

L’idea di base è semplice: invece di ascoltare il click su ogni singolo bottone, ascoltiamo il click su un contenitore comune, come il modale stesso, e poi verifichiamo quale elemento è stato realmente cliccato. È un pattern molto usato nelle applicazioni reali, soprattutto quando il contenuto viene creato o aggiornato dinamicamente.

Codice completo

<div id="modal" class="modal" hidden>
  <div class="modal__content">
    <h2>Gestione utente</h2>
    <p>Scegli un´azione da eseguire.</p>

    <div class="modal__actions">
      <button data-action="save">Salva</button>
      <button data-action="cancel">Annulla</button>
      <button data-action="delete">Elimina</button>
    </div>
  </div>
</div>

<button id="openModal">Apri modale</button>

<script>
  const modal = document.getElementById(´modal´);
  const openModalButton = document.getElementById(´openModal´);

  // Apre il modale
  openModalButton.addEventListener(´click´, () => {
    modal.hidden = false;
  });

  // Delega degli eventi sul contenitore del modale
  modal.addEventListener(´click´, (event) => {
    const actionButton = event.target.closest(´[data-action]´);

    // Se il click non arriva da un elemento con data-action, non fare nulla
    if (!actionButton || !modal.contains(actionButton)) {
      return;
    }

    const action = actionButton.dataset.action;

    switch (action) {
      case ´save´:
        console.log(´Salvataggio dati...´);
        // qui potresti inviare un form o salvare tramite fetch
        modal.hidden = true;
        break;

      case ´cancel´:
        console.log(´Operazione annullata´);
        modal.hidden = true;
        break;

      case ´delete´:
        const confirmed = confirm(´Vuoi davvero eliminare questo elemento?´);
        if (confirmed) {
          console.log(´Elemento eliminato´);
          modal.hidden = true;
        }
        break;

      default:
        console.warn(´Azione non riconosciuta:´, action);
    }
  });

  // Chiude il modale cliccando fuori dal contenuto
  modal.addEventListener(´click´, (event) => {
    const content = modal.querySelector(´.modal__content´);

    if (event.target === modal) {
      modal.hidden = true;
    }

    // Se vuoi chiudere solo cliccando sull´overlay, questo controllo è sufficiente
    // perché il contenuto interno non corrisponde al contenitore esterno.
  });
</script>

Spiegazione

Vediamo il codice passo per passo. Il modale contiene tre pulsanti con un attributo personalizzato data-action. Questo attributo è molto comodo perché ci permette di identificare in modo chiaro il tipo di operazione associata a ciascun pulsante, senza dipendere da classi CSS o da testi visibili che potrebbero cambiare.

1. Apertura del modale

Il pulsante #openModal usa un listener classico con addEventListener per rendere visibile il modale. Qui non serve delega, perché il bottone è uno solo e non cambia nel tempo.

2. Delegazione degli eventi sul modale

Il cuore del tutorial è questo passaggio:

  • aggiungiamo un solo listener al contenitore #modal;
  • quando avviene un click, analizziamo event.target;
  • usiamo closest(´[data-action]´) per risalire al bottone corretto, anche se il click avviene su un elemento interno;
  • leggiamo il valore di data-action e decidiamo cosa fare.

Questo è il vantaggio principale della delega: un solo listener gestisce più elementi. Se in futuro aggiungiamo un quarto pulsante, non dobbiamo registrare un nuovo evento: basta inserire il markup corretto.

3. Perché usare closest

In un bottone reale potresti avere un’icona, uno span o altri elementi interni. Se l’utente clicca sull’icona, event.target non sarà il bottone, ma l’elemento interno. Con closest(´[data-action]´) risaliamo al primo antenato che possiede l’attributo richiesto. Questo rende il codice più robusto e meno fragile.

4. Chiusura cliccando sull’overlay

Un comportamento tipico dei modali è la chiusura cliccando sullo sfondo esterno. Nel nostro esempio controlliamo se event.target === modal. In questo modo il modale si chiude solo quando il click avviene sull’overlay, non sul contenuto interno.

Best practice

  • Usa la delega quando gli elementi sono numerosi o dinamici: è più efficiente e più facile da mantenere.
  • Preferisci attributi semantici come data-action: rendono il codice più leggibile rispetto a controlli basati su testo o classi generiche.
  • Controlla sempre il target dell’evento: non assumere che il click arrivi direttamente sull’elemento atteso.
  • Evita listener duplicati: se apri e chiudi il modale più volte, non registrare più volte gli stessi eventi.
  • Separa logica e presentazione: il CSS deve gestire l’aspetto, JavaScript il comportamento.
  • Usa hidden o classi dedicate per mostrare/nascondere il modale: è una soluzione semplice e chiara.
  • Gestisci i casi non previsti: uno switch con default aiuta a intercettare azioni sconosciute durante il debug.

Riepilogo

In questo tutorial abbiamo visto come combinare addEventListener e delega degli eventi per gestire in modo elegante i click dentro un modale. La strategia è particolarmente utile quando:

  • ci sono più pulsanti con comportamenti diversi;
  • il contenuto del modale può cambiare nel tempo;
  • vuoi evitare di aggiungere un listener per ogni singolo elemento;
  • ti serve un codice più compatto, scalabile e facile da leggere.

Il pattern fondamentale è questo: ascolta l’evento sul contenitore, individua l’elemento cliccato, esegui l’azione corretta. È una tecnica semplice, ma estremamente potente nello sviluppo frontend moderno.

Approfondisci con risorse ufficiali

  • MDN - EventTarget.addEventListener(): documentazione ufficiale sul metodo per registrare eventi.
  • MDN - Event: per capire meglio proprietà come target, currentTarget e il comportamento degli eventi.
  • MDN - Element.closest(): utile per risalire all’antenato corretto durante la delega.
  • MDN - data-*: guida sugli attributi personalizzati data- nel HTML.
  • JavaScript.info - Event delegation: ottima risorsa per approfondire il pattern della delega con esempi pratici.

SHARE