delete row in table with javascript - javascript

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)">×</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.

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)">×</button></td>
</tr>
<tr>
<td>2</td><td>AB</td><td>400</td>
<td><button type="button" onclick="deleteRow(this)">×</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.

You shoud modify your code like this:
btn.onclick = deleteRow;
And the deleteRow declaration to this:
function deleteRow() {
this.parentElement.parentElement.remove();
}

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);
}

Related

Restrict 1st table row for datatables

Hi I am currently working on datatables and I wrote a code when a table row has been click there is a specific function that will be called.
The problem is when I click the table row for the table header it also does the function (IT MUST NOT).
Here is a snippet of my code when I click the table row there will be a function called.
$('#response-contact-container').on('click', 'tr', function(){
var table = $('#response-contact-container').DataTable();
var data = table.row(this).data();
$('#edit-contact-settings').modal('hide');
$('.modal-backdrop').remove();
var community_contacts = ['c_id','firstname','lastname','prefix','office','sitename','number','rel'];
var employee_contacts = ['eid','firstname','lastname','nickname','birthday','email','numbers','grouptags'];
var counter = 1;
var container = document.getElementById("contact-settings-wrapper");
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
for(var i=1; i< data.length; i++) {
var label = document.createElement("label");
var input = document.createElement("input");
if (data[0].charAt(0)=="c") {
var t = document.createTextNode(community_contacts[i].capitalize());
label.appendChild(t);
container.appendChild(label);
input.type = "text";
input.name = community_contacts[i];
input.className = "form-control";
input.value = data[i];
container.appendChild(input);
container.appendChild(document.createElement("br"));
} else {
var t = document.createTextNode(employee_contacts[i].capitalize());
label.appendChild(t);
container.appendChild(label);
input.type = "text";
input.name = community_contacts[i];
input.className = "form-control";
input.value = data[i];
container.appendChild(input);
container.appendChild(document.createElement("br"));
}
console.log(data[i]);
counter++;
}
$('#edit-contact').modal('show');
});
I want the header be able to not perform the function under the onclick in jQuery, but I don't want it to disable because I want to use the datatables built in feature that sort the cells.
Thanks
I interpret your question to be the following: when I click on a table row, can I call a click handler if and only if that row has <td> elements, not <th> elements, i.e. only when it is a non-header row?
To accomplish this, use the jQuery .has() selector. Specifically, in your code, instead of
...on('click', 'tr', ...
use
...on('click', 'tr:has(td)', ...
In the example below, the selected element's currentTarget result shows that it is indeed the row, and not the cell, that is the click's current target. Moreover, it calls the handler function (or not) as follows:
when you click on a normal data row, i.e. a row with all <td> cells
not when you click on a normal header row, i.e. a row with all <th> cells
when you click on a mal-formed row that (inappropriately) contains both <th> and <td> rows
You should never form a table row in the last way. However, that example show how the selector is working. Specifically, even if you click on the <th> cell in that row, the click handler will still fire because you are clicking on a cell in a row that contains at least one <td> cell. That should never be what you want, but it illustrates what's going on in terms of what is actually being selected.
var counter = 0;
$('#myTable').on('click', 'tr:has(td)', function(e) {
console.log(e.currentTarget);
});
$('#myTable').on('click', 'tr', function(e) {
counter += 1;
console.log(counter + ' clicks');
});
table {
border-collapse: collapse;
}
td, th {
border: black solid 1px;
padding: 0.5em;
text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<th>normal header row - cell #1 - <th></th>
<th>normal header row - cell #2 - <th></th>
</tr>
<tr>
<th>malformed (mixed) row - cell #1 - <th></th>
<td>malformed (mixed) row - cell #2 - <td></td>
</tr>
<tr>
<td>normal data row - cell #1 - <td></td>
<td>normal data row - cell #2 - <td></td>
</tr>
</table>

How to get value of text box embeded in cell

I have the following code
<tr val='question'>
<td>
<input style='width: 500px' type='text' placeholder='Q.Enter your question here for radio button? '>
</tr>
How can i find the value of input box embedded in cell .
function saveUserDefQues(){
var table=document.getElementById("QuestionList");
var surveyquestionform=document.forms[0];
var count=$('#QuestionList tr').length
for (var i = 0; i<count; i++) {
var row = table.rows[i];
if(row.getAttribute('val')==='question')
{
var Cells = row.getElementsByTagName("td");;
}
}
}
document.querySelector('tr[val] > td > input').value;
Array.from(document.querySelectorAll('tr[val] > td > input')).forEach(function(entry, index, entries)
{
entry.value; // you may store the value OR process with it AS you see fit
});
Since you are using Jquery this can be done this way.
replace this line of code
var Cells = row.getElementsByTagName("td");
with
var Cells = $(row).find('td');
var inputValue = Cell.find('input').val(); // gives you value of input
Code Refactoring recommended
I would like to refactor your code as below
HTML
<tr data-val='question'> // use data-* attribute to add custom attributes into tags
<td>
<input style='width: 500px' type='text' placeholder='Q.Enter your question here for radio button? '>
</td> // close your td
</tr>
Script
function saveUserDefQues(){
var surveyquestionform = document.forms[0]; // not sure what this is for, so ill leave it as is.
$('#QuestionList tr[data-val="question"]').each(function(){ //loop all tr's which has the data-val set to question
var inputValue = $(this).find('td input').val(); //get the value of input
console.log(inputValue);
});
}
$("tr[val='question'] > td > input").val()
But first you need to write a valid HTML. </td> closing tag is missing. Also you need to put this tr in a <table>.
See this Plunker
function getResult(){
$( "tr" ).each(function( index ) {
console.log($(this).find('input').attr('placeholder') );
});
}

Add JQuery functionality to dynamically created radio buttons

I'm currently trying to add a jQuery function to a row of radio buttons. The problem is that I need to add dynamically many rows. Now For this example I only added 2 elements into the array of newNodes, but in my application newNodes can potentially have many different sizes.
So basically I want to add the Query function something like this:
$('#rowID input').on('change', function() {
alert($('input[name=i]:checked', '#rowID').val());
});
Where it exists inside the forloop and is added for each new row. "rowID" is a variable assigned to the unique row identifier and then use the loop iterator "i" as a way to distinguish the radio buttons for each row.
Here is the HTML:
<form id="createEdges" method="POST>
<fieldset>
<legend class="title">Modify the graph!</legend>
<table id="createEdgesTable">
</table>
<input type="button" class="btn btn-default" id="backToThirdForm" onclick="goBackToForm3()" value="Back"/>
</fieldset>
And Here is the Javascript:
newNodes = [];
newNodes.push(0);
newNodes.push(1);
//get HTML Table to add rows in
var edgeTable = document.getElementById("createEdgesTable");
//Create a table row for each node
for (var i in newNodes) {
var row = edgeTable.insertRow();
row.id = "node" + i;
//Show name of the node
var td = document.createElement('td');
var text = document.createTextNode(newNodes[i]);
td.appendChild(text);
row.appendChild(td);
//Choice for showing node
var td2 = document.createElement('td');
var radioButton1 = document.createElement('input');
radioButton1.type = "radio";
radioButton1.name = i;
radioButton1.value = "showNode";
td2.appendChild(radioButton1);
row.appendChild(td2);
//Choice for creating edge
var td3 = document.createElement('td');
var radioButton2 = document.createElement('input');
radioButton2.type = "radio";
radioButton2.name = i;
radioButton2.value = "createEdge";
td3.appendChild(radioButton2);
row.appendChild(td3);
//Choice for deleting node
var td4 = document.createElement('td');
var radioButton3 = document.createElement('input');
radioButton3.type = "radio";
radioButton3.name = i;
radioButton3.value = "removeNode";
td4.appendChild(radioButton3);
row.appendChild(td4);
var rowID = row.id;
}
$('#node0 input').on('change', function() {
alert($('input[name=0]:checked', '#node0').val());
});
JSFiddle: https://jsfiddle.net/nxexrq9y/
Any example on how to make this work for each row? I'm relatively new to JQuery and have been stuck on this problem for quite some time now. Thank you for your time and help!
Just change your script with following code.
$('tr[id^=node] input').on('change', function() {
alert(this.value);
});
Explanation:
Scripts find any tr whose id starts with node. this covers all your dynamically generated TRs. Further selection narrows down to only input element in each TR, and registers change event for that element. On that change event your have already got that element so you can easily access its value there.
Here is Js Fiddle Link
Further if you want to know clicked radio falls in which node, you can check out this js fiddle.
$('tr[id^=node] input').on('change', function() {
var row = $(this).parents('tr:first').get(0);
alert('Node: '+ row.id+ ' value:' + this.value);
});

JavaScript remove dynamically created tr

I have a js function that adds a tr to a table:
function AddData() {
var rows = "";
var product_id = $('input[name="product_name"]').val();
var product_price = $('input[name="product_price"]').val();
rows += "<td><input type='hidden' name='item_id[]' value='" + product_id + "'><p>" + name + "</p></td><td><input type='hidden' name='price[]' value='" + product_price + "' class='price'></td><td>£<span id='amount' class='amount'>0</span></td><td><div class='btn btn-circle' onclick='RemoveData()' value='" + curtainid + "'>Delete</div></td>";
var tbody = document.querySelector("#myTable tbody");
var tr = document.createElement("tr");
tr.innerHTML = rows;
tbody.appendChild(tr)
update_amounts();
}
Within the <td> is a RemoveData() call. I want this to remove the selected tr from the table. I have tried to use:
function RemoveData() {
var elements = document.getElementById('tr');
last = elements[elements.length-1];
last.parentNode.removeChild(last);
}
but with no success.
getElementById gets a single element, by its id. You're passing in a tag name and expecting it to return a list.
If your goal is to remove the last tr element anywhere on the page, you can use querySelectorAll instead:
function RemoveData() {
var elements = document.querySelectorAll('tr'); // <== Main change
var last = elements[elements.length-1]; // <== Note I added `var`
last.parentNode.removeChild(last);
}
querySelectorAll works on all modern browsers, and IE8.
I added var to the last line because your code was falling prey to The Horror of Implicit Globals without it.
Re your comment below:
How would I remove a selected element...
I'd probably have a single event handler on the table and then trigger removal based on the event's target (e.g., delegated handling). That looks something like this:
"use strict";
var tbody = document.getElementById("the-tbody");
// Add rows when the button is clicked
document.getElementById("btn-add").addEventListener("click", addRow, false);
function addRow(e) {
var row = document.createElement('tr');
row.innerHTML = '<td>Hi there ' +
Math.floor(Math.random() * 1000) +
' <span class="remove">[x]</span></td>';
tbody.appendChild(row);
}
// Remove rows when their ".remove" span is clicked
tbody.addEventListener("click", removeRow, false);
function removeRow(e) {
var elm;
for (elm = e.target; elm !== this; elm = elm.parentNode) {
if (/\bremove\b/.test(elm.className)) { // On modern browsers you could use `classList`
// It's a remove link, remove its parent tr and we're done
removeElement(elm.parentNode);
e.stopPropagation();
return;
}
}
}
function removeElement(elm) {
elm.parentNode.removeChild(elm);
}
.remove {
cursor: pointer;
}
<table>
<tbody id="the-tbody"></tbody>
</table>
<input type="button" id="btn-add" value="Add Row">
There I'm using addEventListener. If you need to support older browsers, you can use the hookEvent function in this other answer instead.
I prefer the jQuery function .closest() to delete the selected row so you don't need to work with an Row-ID...because the threadstarter has already jQuery...try this:
$(document).ready(function(){
$('button[name=deleteTR]').click(function(){
$(this).closest('tr').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr><td><button type="button" name="deleteTR">Delete</button></td><td>Row 1</td></tr>
<tr><td><button type="button" name="deleteTR">Delete</button></td><td>Row 2</td></tr>
<tr><td><button type="button" name="deleteTR">Delete</button></td><td>Row 3</td></tr>
<tr><td><button type="button" name="deleteTR">Delete</button></td><td>Row 4</td></tr>
</table>
Greetings from Vienna

Add/Remove rows dynamically in a table in javascript

I want to add/remove rows in a table dynamically. I have javascript function to add and remove the rows. But, I want the delete button beside every single row so that I can delete a particular row.
ANd I want to add a row only if the first row is completely filled.
function to remove row
function removeRowFromTable()
{
var tbl = document.getElementById('tblSample');
var lastRow = tbl.rows.length;
if (lastRow > 2) tbl.deleteRow(lastRow - 1);
}
function to add rows:
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "text";
cell1.appendChild(element1);
var cell2 = row.insertCell(1);
var element2 = document.createElement("input");
element2.type = "text";
cell2.appendChild(element2);
}
my table:
<table id="tableId">
<tr><td>Host Name</td><td>Directory</td></tr>
<tr><td><input type="text"/></td><td><input type="text"/></td></tr>
<tr><td><input type="button" value="+" onclick="addRow(tableId)"/></td>
<td><input type="button" value="-" onclick="removeRowFromTable()"/></td></tr>
</table>
Any help is appreciated! Thanks in Advance!!!
If you put a delete button on each row, then:
<tr>
<td><input type="button" value="Delete row" onclick="deleteRow(this)">
<td><input type="text">
<td><input type="text">
</tr>
And the deleteRow function can be:
function deleteRow(el) {
// while there are parents, keep going until reach TR
while (el.parentNode && el.tagName.toLowerCase() != 'tr') {
el = el.parentNode;
}
// If el has a parentNode it must be a TR, so delete it
// Don't delte if only 3 rows left in table
if (el.parentNode && el.parentNode.rows.length > 3) {
el.parentNode.removeChild(el);
}
}
BTW, if all your rows have the same content, it will be much faster to add a row by cloning an existing row:
function addRow(tableID) {
var table = document.getElementById(tableID);
if (!table) return;
var newRow = table.rows[1].cloneNode(true);
// Now get the inputs and modify their names
var inputs = newRow.getElementsByTagName('input');
for (var i=0, iLen=inputs.length; i<iLen; i++) {
// Update inputs[i]
}
// Add the new row to the tBody (required for IE)
var tBody = table.tBodies[0];
tBody.insertBefore(newRow, tBody.lastChild);
}
You can avoid a lot of cross browser headaches by using jquery. Here is a sample.
http://jsfiddle.net/piyushjain7/gKJEs/
Javascript has this really useful function called deleteRow where if you know the index you are deleting from, you can simply input that number, and then it'll delete that specific row (index's starting at 0 - tbl.rows.length).
I also found a nice example that uses it in action. You can adjust it to fit your needs though (although his uses checkboxes which might be a lot cleaner than just making a button next to every single row). I don't encourage you to blatantly copy the code so if there is anything that confuses you, please let us know. Hope this helps.
EDIT: I didn't see you wanted to add rows after you found out the last row was completely filled. I'll update my answer when I figure that out. However, the basic idea of that is to check if the <td> tag has text in it (perhaps check if the text inside the tag isn't a blank or if there is a <td> tag at all and then if it isn't empty, make a new <tr> element else don't.
See http://jsfiddle.net/9gnAx/
HTML & JavaScript (body):
<table id="tableId">
<tr>
<th>Host Name</th>
<th>Directory</th>
<td><input class="add" type="button" value="+" /></td>
</tr>
<tr>
<td></td><td></td>
<td><input class="add" type="button" value="+" /></td>
</tr>
</table>
<script type="text/javascript">
(function(){
var els=getElementsByClassName("add","tableId");
for(var i=0;i<els.length;i++){
els[i].onclick=addRow;
}
els[0].onclick();
})();
</script>
CSS (head):
.add,.del{
width:25px;
}
JavaScript (head):
function getElementsByClassName(c,el){
if(typeof el=='string'){el=document.getElementById(el);}
if(!el){el=document;}
if(el.getElementsByClassName){return el.getElementsByClassName(c);}
var arr=[],
allEls=el.getElementsByTagName('*');
for(var i=0;i<allEls.length;i++){
if(allEls[i].className.split(' ').indexOf(c)>-1){arr.push(allEls[i])}
}
return arr;
}
function killMe(el){
return el.parentNode.removeChild(el);
}
function getParentByTagName(el,tag){
tag=tag.toLowerCase();
while(el.nodeName.toLowerCase()!=tag){
el=el.parentNode;
}
return el;
}
function delRow(){
killMe(getParentByTagName(this,'tr'));
}
function addRow() {
var table = getParentByTagName(this,'table')
var lastInputs=table.rows.length>2?
table.rows[table.rows.length-2].getElementsByTagName('input'):[];
for(var i=0;i<lastInputs.length-1;i++){
if(lastInputs[i].value==''){return false;}
}
var rowCount = table.rows.length;
var row = table.insertRow(rowCount-1);
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "text";
cell1.appendChild(element1);
var cell2 = row.insertCell(1);
var element2 = document.createElement("input");
element2.type = "text";
cell2.appendChild(element2);
var cell3 = row.insertCell(2);
var element3 = document.createElement("input");
element3.type = "button";
element3.className="del";
element3.value='-';
element3.onclick=delRow;
cell3.appendChild(element3);
}
Update:
RobG has made me realize that getParentByTagName throws an error if there isn't any parent with the nodeName passed.
If you want a more general getParentByTagName, which doesn't throw errors, you can use
function getParentByTagName(el,tag){
tag=tag.toLowerCase();
while(el&&el.nodeName.toLowerCase()!=tag){
el=el.parentNode;
}
return el||null;
}
And when you call the function you should check if the result is null.
Updated jsfiddle: http://jsfiddle.net/9gnAx/1/

Categories