Poznajemy kolejne sposoby na dodawanie i usuwanie event listenerów. Do dzieła.

Ok, po pierwsze addEventListener to nie jedyna opcja, aby dodać event. Oto inline event:

<button onclick="btnClick()">Click Me</button>

<script>
  function btnClick() {
    console.log("Button Clicked")
  }
</script>

Nie powinno się tego używać. Ale ok, patent na usunięcie:

<button onclick="btnClick()">Click Me</button>
    <script>
        function btnClick() {
          console.log("Button Clicked")
        }
      
        function remove(){
          document.querySelector("button").removeAttribute("onclick");
      }
      </script>

Drugi, też nieidealny sposób na dodawanie eventu (jednego):

<button>Click Me</button>
    <script defer>
        function btnClick() {
          console.log("Button Clicked")
        }
      
        let btn = document.querySelector("button");
        btn.onclick = btnClick;
</script>

Patent na usunięcie – nadpisanie:

<button>Click Me</button>
    <script defer>
        function btnClick() {
          console.log("Button Clicked")
        }
      
        let btn = document.querySelector("button");
        btn.onclick = btnClick;

        function removeOnclick(){
            btn.onclick = function() { return false; };
        }
      </script>

Patent na usuwanie listenera/listenerów, którym daliśmy signal i abort controller:

const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;

button.addEventListener('click', () => console.log('clicked!'), { signal });

// Remove the listener!
controller.abort();

Można wiele naraz. Można używać funkcji anonimowych. Jak chcemy przez removeListener, to musimy mieć funkcje nazwane, już to robiliśmy poprzednio.

A co jeśli nie mamy nazwanych, ale chcemy rozłączyć wszystkie listenery danego elementu?

Taki kod:

class DOMHelper {
  static clearEventListeners(element) {
    const clonedElement = element.cloneNode(true);
    element.replaceWith(clonedElement);
    return clonedElement;
  }

}

Kopiujemy element i wstawiamy w miejsce oryginału. Kopiowanie rozłącza listenery. Także listenery dzieci.

A gdybyśmy chcieli rozłączyć tylko listenery elementu, bez rozłączania dzieci? Wtedy musimy wszystkim jego listenerom nadać signal i wyłączyć abort controllerem.

A gdybyśmy chcieli skopiować element, ale razem z listenerami? Cóż, wtedy mamy problem, niektóre przeglądarki pozwalają uzyskać dostęp do przypiętych listenerów do danego elementu, ale generalnie tutaj warto rozważyć dwie opcje:

  • Delegacja eventów na elemencie głównym i jakiś sposób rozpoznawania delegowanych po klasie, niezależnie gdzie w obrębie głównego się znajdują
  • Zrobić DOM wrapper dla tych elementów (taką warstwę abstrakcji), który dodaje element i eventy, potrafi też skopiować element i ponownie przypiąć eventy trzymane w jakiejś mapie/weakmapie

Tym niemniej to trochę bez sensu kopiować elementy z listenerami, lepiej wykorzystać tag template i komponenty, ale jeżeli chcemy, to jedyną rozsądną opcją jest wrapper, warstwa abstrakcji, która potrafi odtworzyć dodanie event listenerów.