addEventListener nacheinander für mehrere Elemente?
Hi,
ich versuche eine Art Notitzen-App zu coden. Es gibt also eine Seitenleiste in der die verschiedenen Notizen zu sehen sind und wenn diese angeklickt werden, soll der jeweilige Text in der großen textarea angezeigt werden. Bisher habe ich einen Zähler als Variable, der beim Hinzufügen einer neuen Notiz erhöht wird, so wird für jeden neuen Button eine eigene ID erstellt und ich speichere auch alle Notizen in einem Array und kann diese anzeigen lassen. Allerdings muss ich zu jedem Button ein onclick-Element mit der jeweiligen Notiz als Parameter hinzufügen, um sie anzeigen zu können. Das mache ich mit addEventListener. Aber wenn ich einfach document.getElementById(idNames[field]).addEventListener("click", function(){showNotice(toShow)}); verwende, funktioniert der Listener nur für die als letztes hinzugefügte Notitz, wenn ich idNames.forEach(element => document.getElementById(element).addEventListener("click", function(){showNotice(toShow);})) zeigen alle Button beim Klicken natürlich dieselbe Notiz an.
Weiß jemand, was in meinen Fall zu tun ist?
Hier ist der ganze Code:
let field = 0;
let idNames = [];
let allNotices = [];
function add(){ //Fügt dem Sidebar einen Kasten hinzu
textarea = document.getElementById("textfield");
notice = document.getElementById("textfield").value;
sidebar.innerHTML += `<li><button type="button" class="sidebarNotice" id="button`+field+`">${notice}</button></li>`; //Fügt den Kasten hinzu
addOnclick();
textarea.value = ``;//Leert das Textfeld
plus(); //Erhöht field um eins
function plus(){
field++;
}
}
function addOnclick(){ //Fügt zum Array aller idNames den aktuellen ID-Namen hinzu
actual = `button` + field;
idNames.push(actual);
allNotices.push(x);
addOnclick2(); //Führt addOnclick2 für die aktuelle NOtitz aus
}
function addOnclick2(){
toShow = allNotices[field]
console.log(toShow);
document.getElementById(idNames[field]).addEventListener("click", function(){showNotice(toShow)}); //anstelle von forEach
console.log("der EventListener wurde hinzugefügt");
}
function showNotice(x){
console.log("showNotice() wurde ausgeführt")
textarea = document.getElementById("textfield");
textarea.value = x;
}
2 Antworten
Da du auf ein Event des jeweiligen Buttons reagieren möchtest, musst du diesem auch den Listener anhängen.
Dafür gibt es unterschiedliche Lösungswege. Ich stelle einmal drei vor:
a)
const button = document.createElement("button");
button.type = "button";
button.classList.add("sidebarNotice");
button.id = `button${field}`;
button.textContent = notice;
button.addEventListener("click", evt => { /* ... */ });
const listItem = document.createElement("li");
listItem.appendChild(button);
sidebar.appendChild(listItem);
b)
// after innerHTML
sidebar.querySelector(`#button${field}`).addEventListener("click", evt => { /* ... */ });
c)
sidebar.innerHTML += `<li><button onclick="doSomething(this)" type="button" class="sidebarNotice" id="button` + field + `">${notice}</button></li>`;
// doSomething:
function doSomething(sender) {
// ...
}
Die erste Option dürfte in der Performance am schnellsten sein. Beim zweiten Weg müsste der Button erst im DOM gesucht werden, beim dritten Weg wird ein Handler via onclick angehängt.
Bezüglich deines Code würde ich ein paar Verbesserungen und Vereinfachungen vorschlagen.
1) Fasse Notizinhalt und ID zusammen. Du brauchst insgesamt nur ein Array.
const notes = [];
// add:
notes.push({ content: "Hello world!", id: "some-id" });
// find:
const note = notes.find(n => n.id === "searched id");
Alternativ könntest du die Notizen ebenso in einem Objekt speichern, wobei die ID dem Propertynamen entspricht.
const notes = {};
// add
notes["some-id"] = "Hello world!";
// find
const note = notes["searched id"];
Der Button bekommt natürlich wie zuvor auch noch die ID, um später bei Klick die entsprechende Assoziation herstellen zu können.
An der Stelle würde ich allerdings noch hinterfragen, wieso du die Notiz ebenso als Buttonbeschriftung nutzt. Zum einen werden deine Buttons (im Normalfall) so doch ziemlich gestreckt und zum anderen brauchst du dann auch kein Array/Objekt mehr, welches die Notizen separat speichert. Bei Klick kommst du genauso gut via
button.textContent
an den Notizinhalt heran.
2) Die Suche von Elementen im DOM würde ich stets versuchen zu reduzieren. Die Referenz auf das Textfeld kannst du dir global (außerhalb deiner Funktionen) speichern.
const textarea = document.getElementById("textfield");
function add() {
const note = textarea.value;
/* ... */
}
Hinsichtlich deiner textarea-Variable möchte ich zudem anmerken, dass du sie derzeit stets als globale Variable anlegst. Das passiert mit allen Variablen, die du ohne let/const/var deklarierst.
3) Noch zwei weitere unnötige Operationen sind dein Templatestring für das Leeren des Textfelds und die plus-Funktion. Einfacher, schneller und kürzer:
textarea.value = "";
++field;
4) Die Funktionen addOnClick und addOnClick2 braucht es nicht, zumal die zweitgenannte Funktion nicht gut benannt ist.
Innerhalb des Event Handlers kannst du problemlos auf die Attribute des angeklickten Buttons zugreifen.
Beispiel:
button.addEventListener("click", evt => {
// by event object
const clickedButton = evt.currentTarget;
console.log(clickedButton.id);
// by global event object
const clickedButton2 = event.currentTarget;
console.log(clickedButton2.id);
// by button variable from outside
console.log(button.id);
});
Bei Einsatz von onclick (s. o.) verweist der Parameter sender auf den Button.
Entschuldigung, das ist das richtige: https://jsfiddle.net/czpjm5bw/
Du legst die Variable notice global an. Das heißt, immer wenn du eine Notiz anlegst, veränderst du den Wert der gleichen Variable, der bei Klick auch angezeigt wird.
Sie muss als lokale Variable in add angelegt werden.
function add() {
textarea = document.getElementById("textfield");
const notice = textarea.value; // local variable
/* etc. ... */
Das ist absolut unsauber programmiert. Ich erkenne überhaupt keine Logik um da einen Fehler finden zu können. Zu wissen, welche Sprache das ist, wäre auch nett. Ich tippe aber mal auf JS.
Du gibst, wenn ich es richtig verstehe, mehrere Elemente aus. Jedes Element muss eindeutig für den eventListener identifizierbar sein. Sonst geht es nicht. Vermutlich ist es einfacher, wenn du ein onClick-Event direkt in den Code des Elements mit einbaust per Funktion, weil du dann nicht mit den Listenern herumpfuschen musst. Am Ende iterierst du irgendwo falsch und bums geht eine falsche Notiz auf.
Es kann gut, sein, dass dies alles ziemlich umständlich ist, ich bin totaler Anfänger. Ich benutzte kein onclick, da ich die einzelnen Buttons per innerHTML erstelle und ich es dort nicht geschafft habe, Parameter in einer Funktion zu übergeben.
Und entschuldige, du hast recht, ich habe das in JS gecodet.
Dann solltest du vielleicht erstmal kleinere Projekte versuchen :)
Nachdem ich keinen ganzen Code habe, ist es eh schwer zu helfen. Eigentlich ist das nicht wirklich umständlich, wenn man es richtig anstellt...
Am Anfang dachte ich, dass das wirklich klein wäre...
Vielen Dank für deine Antwort! Ich werde meinen Code nach deinen Vorschlägen überarbeiten, bisher habe ich nur den Teil mit dem EventListener ausprobiert und leider hat es nicht funktioniert: jeder Button erhält das onclick Element, aber alle zeigen die selbe Notitz an - den aktuellen Wert von "notice", obwohl sie ja via addEventListener einen anderen Parameter zugewiesen bekommen haben. Anscheinend wird der Parameter aller Buttons auf den neuseten Wert von "notice" aktualisiert.