Changing html table row values indexes with pure Javascript - javascript

I have a scenarion where I delete rows in a html table. Once the row is deleted, I am trying to realign/sort the hidden fields indexes.
for example if second row with hidden fields name[1]abc tr is deleted, then I am trying to generate table with rows having hidden fields with index name[0] and name[1] etc., Any pointers ?
My fiddle
<table class="links-list">
<tbody>
<tr>
<td>test1</td>
<td>test2</td>
<input type="hidden" name="name[0]abc">
<input type="hidden" name="name[0]def">
<input type="hidden" name="name[0]gh1">
</tr>
<tr>
<td>test1</td>
<td>test2</td>
<input type="hidden" name="name[1]abc">
<input type="hidden" name="name[1]def">
<input type="hidden" name="name[1]gh1">
</tr>
<tr>
<td>test1</td>
<td>test2</td>
<input type="hidden" name="name[2]abc">
<input type="hidden" name="name[2]def">
<input type="hidden" name="name[2]gh1">
</tr>
</tbody>
</table>
Javascript
//Loop through table rows
//get all hidden fields for each row
// update index value inside name[index] in sorted order
// like all hidden fields with name[0] in first row name[1] for second row etc
function updateHyperlinkIndexes() {
var linksList = document.querySelector('.links-list tbody');
for (var i = 1; i < linksList.children.length; i++) {
var trContent = linksList.children[i];
for (var i = 0; i < trContent.children.length; i++) {
if (trContent.children.item(i).type && trContent.children.item(i).type === "hidden") {
var cellName = trContent.children.item(i).name;
trContent.children.item(i).name = cellName.replace(/[.*]/, i);
}
}
}
return linksList;
};
var updatedHtml = updateHyperlinkIndexes();

Found the problem, PFB working updateHyperlinkIndexes() function.
var linksList = document.querySelector('.links-list tbody');
for (var i = 0; i < linksList.children.length; i++) {
var trContent = linksList.children[i];
for (var j = 0; j < trContent.children.length; j++) {
console.log(trContent.children[j]);
if (trContent.children.item(j).type && trContent.children.item(j).type === "hidden") {
var cellName = trContent.children.item(j).name;
trContent.children.item(j).name = cellName.replace(/\[.*?\]/g, '['+i+']');
}
}
}
Changes made include correction of replace regex expression, it should be replace(/\[.*?\]/g, '['+i+']');. And secondly you used same variable i for iterating nested loops.
Hope it helps you.

Related

Pure javascript delete selected rows in html table [duplicate]

This question already has answers here:
Why does firstChild not return the first element?
(5 answers)
Closed 5 years ago.
I am trying to deleted selected or all rows using pure javascript. I am unable to delete selected rows. what was the issue in my fiddle
Edit: First row is header so not considering that.
document.getElementById("delete").addEventListener("click", function() {
var tableRef = document.getElementById('links-list');
var tableRows = document.getElementById("links-list").rows;
var checkedIndexes = [];
for (var i = 1; i < tableRows.length; i++) {
var checkboxSelected = tableRows[i] && tableRows[i].cells[0].firstChild.checked;
if (checkboxSelected) {
checkedIndexes.push(i);
}
}
for (var k = 0; k < checkedIndexes.length; k++) {
tableRef.deleteRow(checkedIndexes[k]);
}
});
This sould be something like the one below, with tableRows[i].querySelector('input').checked, as .firstChild is a textnode. Also, index of tableRows starts with 0.
document.getElementById('delete').addEventListener('click', function() {
var tableRef = document.getElementById('links-list');
var tableRows = document.getElementById('links-list').rows;
var checkedRows = [];
for (var i = 0; i < tableRows.length; i++) {
if (tableRows[i].querySelector('input').checked) {
checkedRows.push(tableRows[i]);
}
}
for (var k = 0; k < checkedRows.length; k++) {
checkedRows[k].parentNode.removeChild(checkedRows[k]);
}
});
As the last loop alters the dom, deleting based on indexes is not reliable when multiple rows are deleted in the same time. So instead of the pure indexes, it should iterate through the actual nodes.
You can use the document.querySelectorAll method with the proper css selector to get all the checkboxes that are checked. Then from the table you can remove those rows with checked checkboxes.
let tableRef = document.getElementById('links-list');
let tbody = tableRef.querySelector("tbody");
let checkedInputs = document.querySelectorAll("input[type='checkbox']:checked");
Array.prototype.slice.call(checkedInputs)
.forEach( input => tbody.removeChild(input.parentNode.parentNode))
Can also be writen with es7 syntax like this
[...checkedInputs].forEach( input => tbody.removeChild(input.parentNode.parentNode))
Use the children property instead of the firstChild one. Also you can enhance your code by avoiding element recalculation. For example, you already found the table, so get the row from it.
Also when you're removing rows, start from the end and go up.
document.getElementById("delete").addEventListener("click", function() {
var tableRef = document.getElementById('links-list');
var tableRows = tableRef.rows;
var checkedIndexes = [];
for (var i = 0; i < tableRows.length; i++) {
var checkboxSelected = tableRows[i].cells[0].children[0].checked;
if (checkboxSelected) {
checkedIndexes.push(i);
}
}
for (var k = checkedIndexes.length - 1; k >= 0; k--) {
tableRef.deleteRow(checkedIndexes[k]);
}
});
<table id="links-list">
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test1
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test2
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test3
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test4
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test5
</td>
</tr>
</table>
<input type=button value="delete" id="delete">
You have 2 errors, first you are not getting the value correctly; secondly, you are deleting in the list that you are iterating, so you need to fix that. Try this:
document.getElementById("delete").addEventListener("click", function() {
var tableRef = document.getElementById('links-list');
var tableRows = document.getElementById("links-list").rows;
var checkedIndexes = [];
for (var i = 1; i < tableRows.length; i++) {
var checkboxSelected = tableRows[i] && tableRows[i].cells[0].firstElementChild.checked;
if (checkboxSelected) {
checkedIndexes.push(i);
}
}
for (var k = 0; k < checkedIndexes.length; k++) {
tableRef.deleteRow(checkedIndexes[k]-k);
}
});
fiddle

Do calculation dynamically when inputting the numbers in corresponding row - Javascript

There are m students and n criteria columns in a student row and a total column in the same row. But the total has to be calculated dynamically when inputting the numbers in corresponding row only. what all modifications needed? In this manner, all the inputs in the first row are summed up. But only row-wise summing needed.
<script>
var num=[];
function recalculate(rowData,studCode) {
var n = document.getElementById('criteria_count').value;
num.push(parseFloat(document.getElementById('criteria_mark_'+rowData).value));
var total=0;
for (var i = 0; i <n; i++) {
total = total + parseFloat(num[i]) ;
if (!isNaN(total)) {
document.getElementById('total_mark_'+studCode).value = Math.round(total);
}
}
}
</script>
Hopefully I understand your requirements correctly. I made a JSFiddle detailing how to achieve what you have explained (assuming I understood you correctly).
https://jsfiddle.net/z0d4y8ao/12/
This is looking through each on the specified row, and is calculating the total and putting it separately into a result element.
If you use this code keep in mind that it is raw javascript and that you will have to find the result yourself so you can insert the total value, (personally I create unique ID's with the server side language.).
function calcNewVal(rowID)
{
var row = document.getElementById(rowID);
var tdCount = row.childElementCount - 1;
var total = 0;
var currentTd = null;
var resultText = document.getElementById('result0');
for(var i = 0; i < tdCount; i++)
{
currentTd = row.children[i].childNodes[0].value;
total += parseInt(currentTd);
}
console.log(total);
resultText.innerHTML = total;
}
the html:
<table id="myTable">
<tr>
<th>Subject1</th>
<th>Subject2</th>
<th>Subject3</th>
<th>Result</th>
</tr>
<tr onchange="calcNewVal(this.id)" id="row0">
<td><input type="text" value="13"></td>
<td><input type="text" value="13"></td>
<td><input type="text" value="13"></td>
<td id="result0"></td>
</tr>
<tr id="row1">
<td><input type="text" value="13"></td>
<td><input type="text" value="13"></td>
<td><input type="text" value="13"></td>
<td id="result1"></td>
</tr>

Getting the values from textfield to save as PDF

I already can retrieve every values on my cell depending on what the user input. Using this.
$("#customFields > tbody tr > td").each(function()
{
console.log($(this).find("input").val());
});
But I'm just having a little problem on how can I append user input in the textfield? Becasue when I save as a pdf I got a crumpled <input type="text" class="form-control"> in one cell and it's not getting the values that I input. Screenshot below.
Screenshot:
Is there a way how can I input that values that I inserted here in every cell? I'm stuck in this part I need opinion from others how can I do this.
Table:
<div class = "col-md-12">
<table class = "table" id = "customFields">
<thead>
<tr>
<th>Stock No.</th>
<th>Unit</th>
<th>Description</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" class="form-control"></td>
<td><input type="text" class="form-control"></td>
<td><input type="text" class="form-control"></td>
<td><input type="text" class="form-control"></td>
</tr>
</tbody>
</table>
<button type = "submit" class = "btn btn-primary" id = "addMore">+ Add</button>
<button type = "submit" class = "btn btn-danger" id = "removeRow">- Remove</button>
<button type = "submit" class = "btn btn-primary" id = "save">Save</button>
</div>
Script:
$("#customFields > tbody tr > td").each(function() {
console.log($(this).find("input").val());
});
function tableToJson(table) {
var data = [];
// first row needs to be headers
var headers = [];
for (var i = 0; i < table.rows[0].cells.length; i++) {
headers[i] = table.rows[0].cells[i].innerHTML.replace();
}
data.push(headers);
// go through cells
for (var i = 1; i < table.rows.length; i++) {
var tableRow = table.rows[i];
var rowData = {};
for (var j = 0; j < tableRow.cells.length; j++) {
rowData[headers[j]] = tableRow.cells[j].innerHTML;
}
data.push(rowData);
}
return data;
}
function genPDF() {
//tableToJson is a special function which converts HTML object to Javascript Object Notation
var table = tableToJson($('#customFields').get(0));
//Defining pdf object
var doc = new jsPDF('1', 'pt', 'letter', true);
doc.cellInitialize();
$.each(table, function(i, row) {
$.each(row, function(j, cell) {
doc.cell(1, 10, 90, 20, cell, i);
});
});
doc.save('text.pdf');
}
javascript: genPDF();
Replace your source code to:
for (var j = 0; j < tableRow.cells.length; j++) {
rowData[headers[j]] = tableRow.cells[j].children[0].value;
alert(rowData[headers[j]]);
}
This is my test
Hope this can help you. xD

Why can I filter by int but not string?

Right now I have code that can filter by int:
<input name='tablefilter' type='checkbox' value='1' id='tablefilter1' checked/>
<label for='tablefilter1'>1</label>
<input name='tablefilter' type='checkbox' value='2' id='tablefilter2' checked/>
<label for='tablefilter2'>2</label>
<input name='tablefilter' type='checkbox' value='3' id='tablefilter3' checked/>
<label for='tablefilter3'>3</label>
<table>
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody id='tablebody'>
<tr>
<td>1</td>
<td>One</td>
<td>First</td>
</tr>
<tr>
<td>2</td>
<td>Two</td>
<td>Second</td>
</tr>
<tr>
<td>3</td>
<td>Three</td>
<td>Third</td>
</tr>
</tbody>
</table>
js
/* Demo filtering table using checkboxes. Filters against first td value */
/* Set 'ready' handler' */
document.addEventListener('DOMContentLoaded', initFunc);
/* When document ready, set click handlers for the filter boxes */
function initFunc(event) {
var filters = document.getElementsByName('tablefilter');
for (var i = 0; i < filters.length; i++) {
filters[i].addEventListener('click', buildAndExecFilter);
}
}
/*
This function gets called when clicking on table filter checkboxes.
It builds a list of selected values and then filters the table based on that
*/
function buildAndExecFilter() {
var show = [];
var filters = document.getElementsByName('tablefilter');
for (var i = 0; i < filters.length; i++) {
if (filters[i].checked) {
show.push(filters[i].value);
}
}
execFilter(show); // Filter based on selected values
}
function execFilter(show) {
/* For all rows of table, see if td 0 contains a selected value to filter */
var rows = document.getElementById('tablebody').getElementsByTagName('tr');
for (var i = 0; i < rows.length; i++) {
var display = ""; // Default to display
// If it is not found in the selected filter values, don't show it
if (show.indexOf(rows[i].children[0].textContent) === -1) {
display = "none";
}
// Update the display accordingly
rows[i].style.display = display;
}
}
http://jsfiddle.net/2Lm7pytt/3/
However that filter can't filter by a string. If I for example want to use "one" instead of 1, it wouldn't work.
Does anyone know why and what the solution would be?
Thank you
These lines of your execFilter() method,
if (show.indexOf(rows[i].children[0].textContent) === -1) {
display = "none";
}
is only comparing the index 0 which is the numeric value not other columns.
Unless you compare the values with all the columns (all the indexes of rows[i].children) it won't give you the result you want.
So, you might wan't to run a for loop to iterate through all the children of rows[i].children and compare their text.
var foundResult = false;
for ( var counter = 0; counter < rows[i].children.length; counter++ )
{
if (show.indexOf(rows[i].children[0].textContent) != -1)
{
foundResult= true;
break;
}
}
if ( !foundResult )
{
display = 'none';
}
You mean something like this
var flt = ["zero","one","two","three"];
...
var showIt = show.indexOf(rows[i].children[0].textContent) !=-1;
for (var j=0;j<show.length;j++) {
if (flt[show[j]] == rows[i].children[1].textContent) {
showIt=true;
break;
}
}
rows[i].style.display = showIt?"":"none";

Add table values to input field on button click

I have a DataTable that stores names only. I want to have a button that will add all the names in the DataTable to an text input field.
<div id="myTabDiv">
<table name="mytab" id="mytab1">
<thead>
<tr>
<th>name</th>
</tr>
</thead>
<tbody>
<tr>
<td>chris</td>
</tr>
<tr>
<td>mike</td>
</tr>
</tbody>
</table>
<button id="add" >ADD</button>
<input type="text" id="text">
</div>
After click the "add" button, I want the names to appear in the text field separated by a comma.
And if possible, If the button is clicked again, remove the names?
I created the whole solution on codepen. This is the function used:
var clicks = 0;
function csv() {
var box = document.getElementsByName('text')[0];
if(clicks === 0){
var newcsv = "";
var tds = document.getElementsByTagName("TD");
for(var i = 0; i < tds.length; i++)
{
newcsv += tds[i].innerHTML;
if(i != tds.length-1) newcsv += ",";
}
box.value = newcsv;
clicks++;
}
else{
clicks = 0;
box.value = "";
}
}
This is bound to onclick event of a button.
Assign id to input
<input type=text id="textbox"/>
Just loop though table
var table = document.getElementById("mytab1");
var textbox=document.getElementById("textbox")
for (var i = 0, row; row = table.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
if(textbox.value=="")
{
textbox.value=row.cells[j].innerText;
}
else
{
textbox.value+= textbox.value+','+row.cells[j].innerText;
}
}
}

Categories