Skip to content

Accordion Event delegation

Wir haben nun auf jeden einzelnen Accordeon-Header einen EventListener gelegt. Das ist okay bei vier Accordeons, aber wenn wir … viele haben, wird das ineffizient. Das ist ein Fall für das Event Delegation Pattern.

Beim Event Delegation Pattern legen wir einen Event-Listener auf das nächstgelegene übergeordnete Element und schauen anschließend, wo genau das Event herkommt.

Ein übergeordnetes Element bauen wir uns jetzt noch schnell ein:

<div class="accordion-container">
<div class="accordion">...</div>
<div class="accordion">...</div>
<div class="accordion">...</div>
<div class="accordion">...</div>
</div>

Auf diesen Container legen wir jetzt unseren Event Listener:

const accordionContainer = document.querySelector('.accordion-container');
accordionContainer.addEventListener('click', e => {
// okay, was jetzt?
// loggen wir mal, woher der Event kommt:
console.log(e.target);
});

Jetzt können wir auf alle Events innerhalb des Accordeon-Containers lauschen. Das e.target ist das Element, auf das geklickt wurde.

Wenn ein Accordeon-Header geklickt wurde, möchten wir das zugehörige Accordeon öffnen oder schließen. Wenn irgendwo anders hingeklickt wurde (z.B. auf einen geöffneten Accordeon-Inhalte), soll nichts passieren.

Dafür müssen wir feststellen, ob .accordion-header ein Vorfahr von e.target ist (wir zielen dabei auf <h2>, <button>, <span class="accordion-title"> bzw. <div class="accordion-indicator"> ab).

accordionContainer.addEventListener('click'), e => {
const accordionHeader = e.target.closest('.accordion-header');
if (accordionHeader) {
// toggle acc
} else {
// do nothing - können wir uns hier sparen ...
}
}

Wenn der Klick irgendwo in den Accordion-Header gegangen ist, dann wollen wir dem zugehörigen Accordion die Klasse is-open mitgeben (oder sie wieder wegnehmen). Im HTML sehen wir, dass <div class="accordion"> das Elternelement von <div class="accordion-header"> ist.

accordionContainer.addEventListener('click', e => {
const accordionHeader = e.target.closest('.accordion-header');
if (accordionHeader) {
const accordion = accordionHeader.parentElement;
accordion.classList.toggle('is-open');
}
});