I have made an HTML table and I’ve populated using Local JSON data. I’ve made the table such that it has an edit button and I want it such that when I click on the button it makes the input boxes editable on the respective row.
I’ve got it somewhat working but my code makes it such that when I click on the edit button icon for any row, it will only make it that the TOP row is editable and not the current row that I clicked the edit icon on. Here is my code.
function buildTable(data) {
var table =document.getElementById("myTable")
for (let i =0; i < data.length; i++) {
let row = `<tr>
<td>${[i+1]}</td>
<td id=customerKey>${data[i].customerKey}</td>
<td id=currency>${data[i].currency}</td>
<td id=currency>${data[i].suffix}</td>
<td><button type="button" onclick="editRow()>
</tr>`
table.innerHTML += row
}
}
My function for editRow()
is
function editRow() {
document.getElementById("customerKey").contentEditable = true;
document.getElementById("currency").contentEditable = true;
document.getElementById("suffix").contentEditable = true;
I am not sure why its only targeting the top row of the table and not the respective row that I’ve clicked the icon on though? Or is there a better way to do this?
3
Answers
For one, ids must be unique – yours are the same on each row and it’s finding the first one. Then, you need to find all the related
<td>
s and make them contentEditable = true. Also, you don’t have any input boxes. You have table cells that you are making the content editable. You could easily use inputs and initialize them as disabled and then set disabled to false.You can choose to assign a unique
id
for each of your table cells / elements:The other answers have explained why your current code doesn’t work:
ids
need to be unique. So a) when you loop over your data you’re adding the same ids to each row, and b) when you come to target those row cells the browser will return the first element that matches your query selector ie only the cells in the first row. You can overcome this, as they suggest, by adding the index to the id for each cells, or by using classes or…Data attributes can be very useful here rather than element ids. You can add one identifying the row by index, and one on each cell to identify its type. When you click a button/edit a field you can use
closest
to find the closest row which in turn will identify which object in the array should be updated/delete etc.For example: when you iterate over the data you would add an
rowid
data attribute to the row:and a
celltype
to each cell:When you click on a button, for example, you can then use
closest
to find the closest row, and perform an action on it. Here we’re removing a row from the table when a "delete" button is clicked.The question remains how you’re going to ensure that the changes to the table are fed back into the dataset. I don’t know if you’ve got this far but I took the liberty of writing and documenting a small example. It deviates a little from your code question but you might find some of the code here useful.
It uses basic state-management principles from Redux – a reducer that returns a new state based on actions passed to it, and a store that returns two function
dispatch
andgetState
which can be used to update the state, and get data from it.The table cells are editable from the outset so no need to click a button to enable editing. The only button is the delete button.
When the delete button is clicked the handler grabs the
rowid
from the row element’s data attribute, dispatches an action to the store to remove the row object form the data, and then removes the row.When an input field is changed the handler grabs the
rowid
, the cell’scelltype
data attribute value, and the input value, and dispatches that information to the store which returns a new state where the object identified by therowid
is updated with the new value.