How to append a whole new column to an existing table? - javascript

As the title says, I'm looking to add a new column to a table that exists which you can see here: https://onetoso.com/PSOTesting/Shane/HTML/customCookieList.html
My blocker right now is the tr does not have a class name so I can't append to each row. I've created a new column header by doing:
This creates a new th so I need to generate the field underneath it as well for each respective row.
let newHead = document.createElement('th'); newHead.class = 'ot-table-header'; newHead.innerHTML = 'Description'; document.querySelector('tr').appendChild(newHead);
To add the necessary field I require to the table I have this:
let newRow = document.createElement('td'); newRow.class = 'ot-cookie-desc-td'; newRow.innerHTML = 'Example text'; document.querySelector('tbody tr').appendChild(newRow);
This will add 1 td that I require but how would I add to the additional rows that already exist since there is no way to specifically target those? I'm looking to copy the same format as the existing table.

This is a demo showing how to add a column to a table already existing in the dom.
The function addColumn(table, headerText, rowContents) given a table, the text of the header for the new column and column data contained by each row; just adds the new column to the table as specified by the args.
The demo calls such function inside the useCase() that gets triggered when the button gets clicked.
The table used was taken from the link included in your question but to be better focused I stripped off the details that were just adding noise.
It's worthwhile saying that there's no indicators in your tables to select them in a page holding multiple ones. So in absence of ids or a combination of css class that would make a non ambiguos selector, in my demo I just picked it with document.querySelector('table')
function useCase(){
const table = document.querySelector('table');
addColumn(table, 'newColumn', ['NewContentForRow1','NewContentForRow2']);
}
function addColumn(table, headerText, rowContents){
const newHeaderCol = document.createElement('th');
newHeaderCol.innerText = headerText;
table.querySelector('thead > tr:first-child').append(newHeaderCol);
const tableRows = table.querySelectorAll('tbody > tr');
let iRow = 0;
for(const tableRow of tableRows){
const newBodyCol = document.createElement('td');
newBodyCol.innerText = rowContents[iRow++];
tableRow.append(newBodyCol);
}
}
table, tr, th, td {
border: solid 1px black;
}
button{
margin-top: 1rem;
cursor: pointer;
}
<table>
<caption class="ot-scrn-rdr">Strictly Necessary Cookies</caption>
<thead>
<tr>
<th scope="col" class="ot-table-header ot-host">Cookie Subgroup</th>
<th scope="col" class="ot-table-header ot-cookies">Cookies</th>
<th scope="col" class="ot-table-header ot-cookies-type">Cookies used</th>
<th scope="col" class="ot-table-header ot-life-span">Lifespan</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row1[A]</td>
<td>Row1[B]</td>
<td>Row1[C]</td>
<td>Row1[D]</td>
</tr>
<tr>
<td>Row2[A]</td>
<td>Row2[B]</td>
<td>Row2[C]</td>
<td>Row2[D]</td>
</tr>
</tbody>
</table>
<button onclick="useCase();">Add Column</button>

Related

Cant get the length of my table in java script

I have following HTML code for an table:
<div id="table">
<table>
<thead>
<tr>
<th>Product</th>
<th>net</th>
<th class="green">VAT</th>
</tr>
</thead>
<tbody>
<tr>
<td class="red">Lipstick</td>
<td>€6.58</td>
<td>19</td>
</tr>
<tr>
<td class="red">Shoelaces</td>
<td>€7.34</td>
<td>19</td>
</tr>
<tr>
<td class="apple">Apple</td>
<td>0.43</td>
<td>7</td>
</tr>
</tbody>
</table>
</div>
The table is created with tableify.
Now i want to select a row with this function:
function selectedRow(){
var index,
table = document.getElementById("table");
for(var i = 1; i < table.rows.length; i++)
{
table.rows[i].onclick = function()
{
// remove the background from the previous selected row
if(typeof index !== "undefined"){
table.rows[index].classList.toggle("selected");
}
console.log(typeof index);
// get the selected row index
index = this.rowIndex;
// add class selected to the row
this.classList.toggle("selected");
console.log(typeof index);
};
}
}
selectedRow();
Here is the following CSS code so that the the background geht a color:
.selected{
background-color: brown;
color: #fff;
}
Normally should the row, that i selected turn brown, but i get a error, that length can't be read. If i have a normal table without and >tbody>, the code works.
How can i get the body so that can i read the length and the row?
Now that you updated the question you added a parent div to fetch the child table. So the selector in that case should be: #table > table
Here's a code that achieves that same result in a better way and using addEventListener instead of the onclick property.
Two strategies are shown to listen for the click event:
Having a click event handler for each row
Having a click event handler for the whole table
The first one just listen for the click event for any single row in the table and will check if the table has any selected row before attempting to toggle the class or if the clicked row is the one having the selected class.
The second has one listener for the click event on the table only. Since the event bubble starting from the exact child element clicked (a td for example) it will trigger anyway but it needs to make further checks to better target the context.
In the end...
I left the first strategy cabled with the logics and made it more narrow so that you can select any row at any moment and it will become the only selected row in the table
addClickEventToTableRows();
//adds a click event handler to the table
function addClickEventToTable(){
const table = document.querySelector("#table table");
table.addEventListener('click', tableOnClick);
}
//the click event handler for the table
function tableOnClick(event){
const clickedElement = event.target;
const hasTbodyAsParent = clickedElement.closest('tbody') !== null;
//if the child element clicked of the table, is a child of tbody
if ( hasTbodyAsParent ){
//the clickedrow taken with .closest (since clickedElement could be a td)
const clickedRow = clickedElement.closest('tr');
clickedRow.classList.toggle("selected");
clickedRow.closest('table').removeEventListener('click', tableOnClick);
}
}
//adds a click event handler to all the rows of the table
function addClickEventToTableRows(){
//the table element
const table = document.querySelector("#table table");
//foreach row element in the tbody of the currently selected table
table.querySelectorAll(':scope > tbody > tr')
.forEach(row => {
//add a click event listener to the current row
row.addEventListener('click', (event)=>{
//retrieves the clicked table row
const clickedRow = event.currentTarget;
console.log(`Row: ${clickedRow.rowIndex} was clicked`);
//if there's not any row in the table with the 'selected' class OR this row has the class selected
//if(!clickedRow.closest('tbody').querySelector('.selected') || clickedRow.classList.contains('selected'))
table.querySelectorAll(':scope > tbody > tr.selected').forEach(trSelected => {
trSelected.classList.remove('selected');
});
//toggle its selected class
clickedRow.classList.toggle("selected");
});
});
}
#table > table > tbody > tr{
cursor: pointer;
}
#table > table{
border-collapse: collapse;
}
#table > table > tbody td{
border: solid 1px lightgray;
padding: 1rem;
}
#table > table > thead th{
background: gray;
color: white;
font-weight: 600;
font-size: 1.5rem;
padding: .5rem;
}
.selected {
background-color: brown;
color: #fff;
}
<div id="table">
<table>
<thead>
<tr>
<th>Product</th>
<th>net</th>
<th class="green">VAT</th>
</tr>
</thead>
<tbody>
<tr>
<td class="red">Lipstick</td>
<td>€6.58</td>
<td>19</td>
</tr>
<tr>
<td class="red">Shoelaces</td>
<td>€7.34</td>
<td>19</td>
</tr>
<tr>
<td class="apple">Apple</td>
<td>0.43</td>
<td>7</td>
</tr>
</tbody>
</table>
</div>

How to delete HTML column with dynamic header <th> name

I have a script that able to add new column to a HTML table. When user press add group the header will become Group1, Group2 and so on.. Currently im adding a delete group function that able to delete all the added column. So now the problem is when I delete a column and add again a new column , the name Group(x) will not be reset.
For example:user add group1 and group2 after that he delete group2. The next time he press add group again, it will show group3 instead of group2
Image:
Expected Output: The column name should be reset whenever the column is deleted.
Html:
<table id="persons" border="1">
<thead id="theadID">
<tr>
<th>Name</th>
<th>sex</th>
<th>Message</th>
</tr>
</thead>
<tbody id="tbodyID">
<tr>
<td>Viktor</td>
<td>Male</td>
<td>etc</td>
</tr>
<tr>
<td>Melissa</td>
<td>Female</td>
<td>etc</td>
</tr>
<tr>
<td>Joe</td>
<td>Male</td>
<td>etc</td>
</tr>
</tbody>
</table>
<button onclick="javascript:appendColumn()">Add column</button>
<input type="button" onclick="deleteLastColumn();" value="do it"/>
Jquery& Javascript:
function deleteLastColumn() {
$('#persons tr').find('th:last-child, td:last-child').remove()
}
let groupNum = 1;
const tableEl = document.getElementById('persons');
// append column to the HTML table
function appendColumn() {
// open loop for each row and append cell
for (let i = 0; i < tableEl.rows.length; i++) {
createCell(tableEl.rows[i].insertCell(tableEl.rows[i].cells.length), i, 'col');
}
tableEl.rows[0].querySelector('td:last-child').textContent = 'Group' + groupNum;
groupNum++;
}
// create DIV element and append to the table cell
function createCell(cell, text, style) {
var div = document.createElement('div'), // create DIV element
txt = document.createTextNode(text); // create text node
div.appendChild(txt); // append text node to the DIV
div.setAttribute('class', style); // set DIV class attribute
div.setAttribute('className', style); // set DIV class attribute for IE (?!)
cell.appendChild(div); // append DIV to the table cell
}
maybe I'm missing it but I don't see the code which deletes ALL the cols, I only see one. But still the solution seems simple, just decrement the groupNum variable when you delete a col
function deleteLastColumn() {
$('#persons tr').find('th:last-child, td:last-child').remove()
groupNum--;
}

JavaScript single input search multiple html table columns

I am using PHP and MySQL to build an HTML table. I am trying to use JavaScript to filter/search the table and only display the rows with the results I need. I want the JavaScript input to search multiple <td>s of the table. I was able to get this to work, but it is not going to be an elegant solution to put in place with larger tables.
I am sure there is a better way to choose what is being searched, but have not been able to find anything. Does anybody know a way for me to make this code more flexible for varying column width tables?
function myFunction() {
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
td1 = tr[i].getElementsByTagName("td")[1];
if (td+td1) {
if ((td.innerHTML.toUpperCase().indexOf(filter)+td1.innerHTML.toUpperCase().indexOf(filter)) > -2) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search" title="Type in anything">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
There's a lot you can improve. Start by remembering to explicitly declare your variables, otherwise they become global.
This solution doesn't rely on any specific number of columns. It will work no matter how many there are.
See comments inline for more:
// Get DOM references just once:
var input = document.getElementById("myInput");
var table = document.getElementById("myTable");
// Do event binding in JavaScript, not HTML
input.addEventListener("keyup", filter);
input.addEventListener("search", filter);
// Get all rows, except the header and convert to array so .forEach() can be used to loop
var rows = Array.prototype.slice.call(table.querySelectorAll("tr:not(.header)"));
function filter() {
// Always trim user input
var filter = input.value.trim().toUpperCase();
// Loop the rows
rows.forEach(function(row) {
// You really don't need to know if the search criteria
// is in the first or second cell. You only need to know
// if it is in the row.
var data = "";
// Loop over all the cells in the current row and concatenate their text
Array.prototype.slice.call(row.getElementsByTagName("td")).forEach(function(r){
// Don't use .innerHTML unless there is HTML. Use textContent when there isn't.
data += r.textContent;
});
// Check the string for a match and show/hide row as needed
// Don't set individual styles. Add/remove classes instead
if(data.toUpperCase().indexOf(filter) > -1){
// show row
row.classList.remove("hidden");
} else {
// hide row
row.classList.add("hidden");
}
});
}
input[type=search]{
border-radius:10px;
outline:0;
padding:3px;
}
input[type=search]:focus{
box-shadow:0 0 4px blue;
}
.hidden { display:none; }
.leftHeader { width:60%; }
.rightHeader { width:40%; }
<!-- Use the actual "search" input type and don't do inline CSS or JavaScript -->
<input type="search" id="myInput" placeholder="Search" title="Type in anything">
<table id="myTable">
<tr class="header">
<th class="leftHeader">Name</th>
<th class="rightHeader">Country</th>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
All what you have to do is to get the td content and then match it with the search input.
function search(value) {
$('table tr').each(function () {
var content = $(this).find('td').text();
if (content.toUpperCase().includes(value.trim().toUpperCase())) {
$(this).show();
} else {
$(this).hide();
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<body>
<input type="search" placeholder="Search..." id="search_account" onkeyup="search(this.value)">
<table>
<tr>
<td>Cell1</td>
<td>Cell2</td>
<td>Cell3</td>
</tr>
<tr>
<td>Cell4</td>
<td>Cell5</td>
<td>Cell6</td>
</tr>
</table>
</body>
</html>

Javascript: extract cell data from table

I have a scenario where there is a table of 4 rows, in the 4th row is a textbox. When an "onchange" event of the textbox is triggered, I want to extract the data in the cells of the same specific row into another table. and ofcourse my table is consisted of more than one row.
<div class="ProductsTable">
<table class="tablestyle">
<tr>
<th>Item</th>
<th>Price</th>
<th>Preview</th>
<th class="auto-style4">Quantity</th>
<th class="auto-style15">Selected Items</th>
</tr>
<tr id="row1">
<td class="auto-style1" id="item_name">Sofa</td>
<td class="auto-style2" id="item_price">$280.00</td>
<td class="auto-style3">
<img class="itemimage" src="images\sofa1.jpg" />
</td>
<td class="auto-style4">
<input class="quantitybox" id="item_quantity" type="text" onchange="get_quantity();" />
</td>
<td rowspan="10">
<table class="InvoiceTable" id="invoice">
<tr>
<th class="auto-style7">Item</th>
<th class="auto-style2">Price</th>
<th class="auto-style4">Quantity</th>
</tr>
</table>
</td>
</tr>
</table>
</div>
And my javascript is:
function get_quantity() {
var table = document.getElementById("invoice");
var row = table.insertRow(1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2)
cell1.innerHTML = document.getElementById("item_name").innerHTML;
cell2.innerHTML = document.getElementById("item_price").innerHTML;
cell3.innerHTML = document.getElementById("item_quantity").value;
}
How can I create a loop to check through all my table when an "onchange" event is triggered. As I actually have 10 rows in my table.
Preferably without using jquery.
If I understand you correctly you are looking for a function to copy the content of the changed row, that is the data in each column, into the invoice table.
I expect the rows to be created dynamicaly with some sort of iteration. When iterating I expect a unique number is availabe why this can be used as a general selector.
Here is a function to do this:
function get_quantity(rowNumber) {
var table = document.getElementById("invoice" + rowNumber);
var row = table.insertRow(1);
var columns = document.getElementById("row" + rowNumber).childNodes;
var dataColumnIndex = 0;
for (var i = 0; i < columns.length; i++) {
if (columns[i].className == "data") {
var cell = row.insertCell(dataColumnIndex);
cell.innerHTML = columns[i].innerHTML;
dataColumnIndex++;
}
}
var inputQuantity = document.getElementById("item_quantity" + rowNumber).value
row.insertCell(dataColumnIndex).innerHTML = inputQuantity;
}
You select what columns to copy by marking the them with class data.
I gets the invoice table by expecting it to have the id invoice + number. Fx. invoice1. Same goes with each row and the input field.
Here is a plunker with a full example.
Edit
There should only be a single invoice table where all products are added to.
By selecting the same table for row insertion in the function this is fixed.
This updated plunker has the change

change table row class name dynamically using javascript

After hitting ADD button I get yet another row. I need it's row class should be changed accordingly by identifying previous row's class. If previous row class name is odd then newly created class name should be even and so on. How do we do this by using javascript? How can we modify existing code to do this or any other suggestion?
Proper CSS file is ready for alternate class names. When I fetch data from database then alternate odd/even row will be created. But when I hit ADD button it always take first rows class name because there is a clone of first row always. I have no worries for cloned row except class name.
<script>
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);
}
</script>
<table id="table1" border=1 class="display">
<tr class="odd">
<th>Operator ID</th>
<th>Status</th>
</tr>
<tr class="odd">
<td>TestA</td>
<td>ActiveA</td>
</tr>
<tr class="even">
<td>TestB</td>
<td>ActiveB</td>
</tr>
</table>
<input type="button" value="ADDROW" onclick=addRow("table1"); />
Why not just use the proper CSS:
#table1 tr {
/* odd row styles */
/* also acts as fallback for really old browsers */
}
#table1 tr:nth-child(even) {
/* even row styles */
}
You can simply do something like this:
tr:nth-child(even) td {
background-color: #ccc;
}
tr:nth-child(odd) td {
background-color: #fff;
}
DEMO HERE

Categories