Ich wollte eine einfache Liste mit Eingabefeldern bauen und per Javascript jeweils einen Entfernen-Button hinzufügen, und unten einen globalen Hinzufügen-Button, der weitere Eingabefelder produziert. Also im Grunde
<ol>
<li class="guestInput">test1 x </li>
<li class="guestInput">test2 x </li>
<li class="guestInput">test3 x </li>
+
</ol>
mit Buttons.
Das war auch eigentlich kein Problem. Hier die Funktion zum Spawnen des Entfernen-Buttons:
function addRemoveButton(index) {
var removeButton = document.createElement("button");
removeButton.type = "button";
removeButton.className = "remove icon-trash";
document.querySelectorAll(".guestInput")[index].appendChild(removeButton);
removeButton.addEventListener("click", function() {
this.parentNode.parentNode.removeChild(this.parentNode);
});
}
Und so sah der JS-Code des Hinzufügen-Buttons aus:
var add = document.createElement("button");
add.type = "button";
add.className = "icon-plus";
add.addEventListener("click", function() {
var http = new XMLHttpRequest();
http.onreadystatechange = function() {
if (http.readyState == 4 && http.status == 200) {
document.querySelector("#guestList").innerHTML += http.responseText;
addRemoveButton(document.querySelectorAll(".guestInput").length-1);
}
}
currentLength = document.querySelectorAll(".guestInput").length;
http.open("GET","/guestInput?index="+ currentLength, true);
http.send();
});
Per Ajax wird das HTML eines Eingabefelder geholt und dieses dann der Liste hinzugefügt.
Das Problem war, dass es so nicht funktioniert. Bei jedem Hinzufügen eines Eingabefeldes verschwanden alle alten Event-Handler.
Meine erste Lösung sah so aus:
function addRemoveButton(i) {
var removeButton = document.createElement("button");
removeButton.type = "button";
removeButton.className = "remove icon-trash";
removeButton.dataset["index"] = i;
document.querySelectorAll(".guestInput")[i].appendChild(removeButton);
removeButtons = document.querySelectorAll(".remove");
for (var j = 0; j < removeButtons.length; j++) {
removeButtons[j].addEventListener("click", function() {
document.querySelectorAll(".guestInput")[this.dataset["index"]].parentNode.removeChild(document.querySelectorAll(".guestInput")[this.dataset["index"]]);
});
}
}
Da sind zwei Lösungsansätze vermischt:
- Falles es ein Scope-Problem sein sollte, werden die Index-Positionen im Dataset gespeichert und daraus gelesen.
- Als das nicht half kam die Brechstange: Jedes mal alle Event-Handler neu setzen
Absolut hässlich, aber ich kam einfach nicht darauf, wo das Problem liegt.
Dank einer Reihe von Fiddles kam ich nun darauf: Das Problem ist oben, beim Handler des Hinzufügen-Buttons:
document.querySelector("#guestList").innerHTML += http.responseText;
Durch die Manipulation per innerHTML werden die Event-Handler gelöscht. Die Lösung ist, regulär ein Element zu erstellen:
var newGuestInput = document.createElement("li");
newGuestInput.className = "guestInput";
newGuestInput.innerHTML = http.responseText;
document.querySelector("#guestList").appendChild(newGuestInput);
Blöd ist, dass dafür Teile (der Klassenname und das li) statt per Template per Javascript gesetzt werden müssen. Aber trotzdem ist das Ergebnis wesentlich schöner als der Murks vorher.