1

Apologies if something similar has been posted but I am trying to delete a row the button is on and not just the last row as the search results seem to give me.

I have the following code that adds to an HTML table but onclick doesn't work, the delete button doesn't work and addRow doesn't function. Why not?

java code

function addRow() {

  var table = document.getElementById("createOrderTable");
  var rowCount = table.rows.length;
  var row = table.insertRow(rowCount);

  ... other cells ...

  var cell4 = row.insertCell(3);
  var btn = document.createElement("input");
  btn.type = "button";
  btn.value = "Close";
  btn.onclick = deleteRow('createOrderTable', rowCount);
  cell4.appendChild(btn); 

}

function deleteRow(id, row) {
  document.getElementById(id).deleteRow(row);
}

table code

<table id="createOrderTable" width="100%">                   
  <tr>
    <th>Count</th><th>Product</th><th>Mesh</th><th>Delete</th>
  </tr>
  <tr>
    <td>1</td><td>OL</td><td>200</td><td><button type="button" class="close" aria-hidden="true" onclick="deleteRow('createOrderTable', 1)">&times;</button></td>
  </tr>
</table>

if I change

btn.onclick = deleteRow('createOrderTable', rowCount );

to

btn.onclick = deleteRow('createOrderTable', rowCount + 1 );

I can get the row to show but it throws

Uncaught IndexSizeError: Failed to execute 'deleteRow' on 'HTMLTableElement': The index provided (3) is greater than the number of rows in the table (3).

and doesn't show the button. I'm confused about what I'm doing wrong here.

6
  • 2
    You know what is the difference between function call and a reference? Just apply that knowledge, when you assign an event handler to btn. Commented Jan 19, 2016 at 20:17
  • Ah I see what you mean Teemu, I come from Java and am new to this way of doing things.. how can i reference a function with parameters? Commented Jan 19, 2016 at 20:25
  • You wrap the invokation in a function expression: function () {deleteRow('createOrderTable', rowCount);}. Please read also Maxali's answer, they have pointed an important issue too. Commented Jan 19, 2016 at 20:28
  • Ah that worked, and its functioning now. I am looking at Maxali's answer right now and his changes are having some unintended side effects but I'll post those down there. Commented Jan 19, 2016 at 20:34
  • 1
    Wait! There will be more problems. After adding a couple of rows you'll remove some of them randomly (i.e. not always the last-one). rowCount will point to a row position which it had when it was created, but that position might be wrong at the time you remove a row. I'd get parentElement.parentElement.rowIndex of the clicked button, and used that as an index to pass to table.deleteRow method. Commented Jan 19, 2016 at 20:41

3 Answers 3

3

The row index is not static, so as you delete rows, the row index of remaining rows can change if a row with a lower index is deleted. A solution is to not use rowIndex at all, and just use DOM relationships instead.

You can get a reference to the button that was clicked by passing this to the function, then go up parent nodes until you reach a TR element and delete it, e.g.

// Helper function:
function upTo(el, tagName) {
  tagName = tagName.toLowerCase();

  while (el && el.parentNode) {
    el = el.parentNode;
    if (el.tagName && el.tagName.toLowerCase() == tagName) {
      return el;
    }
  }
  return null;
}    

function deleteRow(el) {
  var row = upTo(el, 'tr')
  if (row) row.parentNode.removeChild(row);
}
<table>
  <tr>
    <td>1</td><td>OL</td><td>200</td>
    <td><button type="button" onclick="deleteRow(this)">&times;</button></td>
  </tr>
  <tr>
    <td>2</td><td>AB</td><td>400</td>
    <td><button type="button" onclick="deleteRow(this)">&times;</button></td>
  </tr>
</table>

You can also use event delegation and put a single listener on the table, then use the associated event object's target property to see if the event was initiated by a click on a button with class close. If so, call deleteRow and pass the element reference as a parameter as for the above.

Sign up to request clarification or add additional context in comments.

Comments

1

You shoud modify your code like this:

btn.onclick = deleteRow;

And the deleteRow declaration to this:

function deleteRow() {
    this.parentElement.parentElement.remove();
}

Comments

1

UPDATE

Check working example.

To delete the current row that the button belongs to Change onclick of <button> to :

onclick="this.parentNode.parentNode.parentNode.deleteRow(this.parentNode.parentNode.rowIndex)"

or change button in html like:

<input type="button" onclick="deleteRow(this)">X</button>

or by JavaScript code using

btn.setAttribute('onclick','deleteRow(this)');

Delete function is like:

function deleteRow(el) {
    var tbl = el.parentNode.parentNode.parentNode;
    var row = el.parentNode.parentNode.rowIndex;

    tbl.deleteRow(row);
}

5 Comments

There is an initial row provided, but that can also be deleted.
I'm getting Cannot read property 'parentNode' of undefined is there too many parent nodes?
@Maxali I understand your live example but that ignores that I'm adding rows to the table programmatically via the addRows function.
@john You add rows in your normal way. But set onclick event like btn.setAttribute('onclick','deleteRow(this)'); instead of btn.onclick

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.