Hallo Henry,
es gibt zwei mögliche Vorgehensweisen, und wenn man sie miteinander mischt, muss man aufpassen.
(1) tr und td Elemente mit createElement erzeugen und mit appendChild sinnvoll einfügen
(2) tr und td Elemente mit insertRow und insertCell erzeugen
Du erzeugst einmalig mit createElement ein tr und ein td Element und hantierst dann damit herum. Das ist aber sinnlos, weil Du ja eigentlich von row=tbody.insertRow() ein neues tr Element in diesem tbody bekommst und von row=insertCell() ein neues td Element in dieser Zeile.
Du erzeugst pro Datensatz ein row Element. Das ist richtig. Und dann erzeugst Du genau ein cell Element. Das ist nicht richtig, du musst pro Datenspalte einen insertCell() Aufruf machen.
Sodann machst Du dreimal hintereinander eine Zuweisung an td.textContent und fügst td mit appendChild an tr an. Das ist aber jedesmal die gleiche Zelle, du hast kein neues td Element erzeugt. Deswegen hast Du in tr am Ende nur ein td Element drin (der appendChild reißt es erstmal von seinem Parent weg und fügt es dann neu ein) und der textContent entspricht der letzten Zuweisung: del.
Darauf folgt dann die Iteration über die Objekteigenschaften. Du rufst zwar pro Eigenschaft einmal row.insertCell() auf, tust mit der so erhaltenen cell (ein td-Element) aber nichts. Statt dessen überschreibst Du erneut dein Einmal-td.
Und dann machst Du mit der nächsten Zeile weiter, hast aber die Row nicht an die Table angehängt.
Schmeiß die Variablen tr und td weg und den createElement Aufruf dazu auch.
insertRow() hängt dem tbody eine row an und liefert Dir das tr Element. insertCell() hängt der row eine cell an und liefert Dir das td Element.
Rufe pro gewünschter Spalte in der Row einmal cell=row.insertCell() auf und speichere den Text, der da rein soll, dann mit cell.textContent. Ein appendChild ist weder für row noch cell nötig, das machen die insert-Methoden automatisch.
Und, ach ja, such Dir das tbody-Element mit document.querySelector("#myTable tbody") heraus. Das ist der effizienteste Weg, den ersten (oder einzigen oder impliziten) tbody einer Tabelle mit id="myTable" zu finden.
Sortiere deinen Code besser. Die Funktion heißt addRow, aber sie fügt alle Rows hinzu. Sie müsste also addRows heißen. Das würde ich aber nicht tun, statt dessen sollte es so aussehen:
function onloadstart() {
const myBody = document.querySelector("#myTable tbody");
dataPoints.forEach((dataPoint, index) => addRow(myBody, dataPoint, index));
myBody.addEventListener("click", handleDatapointClick);
}
function addRow(tbody, dataPoint, index) {
const row = tbody.insertRow();
row.dataset.index = index; // Zeilenindex als data-index Attribut speichern
// insertCell fügt ein td ein und gibt es zurück, d.h. man kann sofort
// eine Zuweisung an textContent machen und muss es nicht speichern
row.insertCell().textContent = "add";
row.insertCell().textContent = "edit";
row.insertCell().textContent = "del";
Object.values(dataPoint)
.forEach(value => row.insertCell().textContent = value);
}
function handleDatapointClick(event) {
const cell = event.target.closest("td");
if (!cell) return;
const row = cell.parentElement;
const index = row.dataset.index;
...
}
Es ist sinnvoll, finde ich, die Interation über die dataPoints und das Einfügen eines dataPoint in eine Row zu separieren. Und für den Eventhandler ist es nützlich, den Index der Tabellenzeile im tr-Element zu speichern. Man KANN sich zwar auch auf die rowIndex-Eigenschaft des tr-Elements verlassen, aber ich mache solche Dinge lieber explizit.
Wenn Dich row.insertCell().textContent = ... irritiert - ich hätte auch zu Beginn mit let cell; eine Variable namens cell definieren können und dann jeweils
cell = row.insertCell();
cell.textContent = ...
schreiben können. Aber, wie im Kommentar geschrieben, braucht man die Variable nicht und es geht in einer Zeile, wenn man lediglich textContent setzen muss.
Zum Thema click-Handler pro Row oder gar pro Cell: Das würde ich gar nicht erst versuchen. Registriere genau einen click-Handler auf der Table. Klicks in der Tabelle werden zwar auf td Elementen ausgelöst, blubbern dann aber im DOM nach oben und kommen beim table Element an. In diesem click-Handler kannst Du leicht ermitteln, in welcher Row und in welcher Cell geklickt wurde. Siehe Code oben.
Wenn Du dann Rows hinzufügst, musst Du Dich nicht darum kümmern, einen Eventhandler hinzuzufügen, das Bubbling erledigt das automatisch. Ausführliche Infos zur Ereignisbehandlung findest Du im Wiki.
Rolf
sumpsi - posui - obstruxi