Group column with the same subheader name in datatable using Javascript/jQuery - javascript

I have a table like this
In which I have different city where we have demand-supply of different products.
Now what I want as here demand is different for all the products However supply is the same on all of three product, so I want that table looks like in this manner.
What I want to do is I want only to show the supply column once in the last of the table. This has to be done dynamically as in the future we have multiple products
Can anyone help me with this?

What the code below does is:
Identify the positions of the "Supply"'s and store them in ind array, in this case will be [3, 5, 7]
Loops through ind except for the last element 7(as one "Supply" will be left) and hide all td's; $("td:nth-child("3"), $("td:nth-child("5")
The "Demand"s that precede each of these elements will be assigned two spaces.
let ind = [];
$("td:contains('Supply')").each(function (index) {
ind.push($(this).index() + 1);
});
$(".hide").on("click", function () {
for (let i = 0; i < ind.length - 1; i++) {
let el = $("td:nth-child(" + ind[i] + ")");
el.prev().attr("colspan", "2");
el.hide();
}
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<th>City</th>
<th colspan="2">Product 1</th>
<th colspan="2">Product 2</th>
<th colspan="2">Product 3</th>
</tr>
<tr>
<td></td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
</tr>
<tr>
<td>City 1</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 2</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 3</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 4</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
</table>
<button class="hide">Hide</button>

Related

Hide empty html table rows

Problem
I have a table with one or more empty rows. How to hide empty rows from the table?
For example
1 - John | Alfredo
2 - Mark | Zuck
3 - |
4 - Carl | Johnson
In this case, I'd like to delete the third row.
Step Tried
I found how to delete a specific row, what about deleting all the empty rows?
deleteEmptyRows();
function deleteEmptyRows() {
var myTable = document.getElementById("myTable")
var rowToDelete = 2;
myTable.deleteRow(rowToDelete)
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
</tbody>
</table>
This is how you can dynamically hide empty table rows with javascript.
deleteEmptyRows();
function checkIfCellsAreEmpty(row) {
var cells = row.cells;
var isCellEmpty = false;
for(var j = 0; j < cells.length; j++) {
if(cells[j].innerHTML !== '') {
return isCellEmpty;
}
}
return !isCellEmpty;
}
function deleteEmptyRows() {
var myTable = document.getElementById("myTable");
for(var i = 0; i < myTable.rows.length; i++) {
var isRowEmpty = checkIfCellsAreEmpty(myTable.rows[i]);
if (isRowEmpty) {
myTable.rows[i].style.display = "none";
}
}
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
</tbody>
</table>
Here, a simple method for row is empty (this allows us to check for other conditions easily later).
Loop over rows and call remove if empty.
const rowIsEmpty = (tr) => Array.from(tr.querySelectorAll('td')).every(td => td.innerText === "");
deleteEmptyRows();
function deleteEmptyRows() {
var myTable = document.getElementById("myTable");
myTable.querySelectorAll('tr').forEach(tr => {
if(rowIsEmpty(tr)) tr.remove();
});
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Was answered in another thread.
Jquery: hiding empty table rows
Loops through all table tr rows, and checks td lengths. If the td length is empty will hide.
$("table tr").each(function() {
let cell = $.trim($(this).find('td').text());
if (cell.length == 0){
console.log('Empty cell');
$(this).addClass('nodisplay');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td>
</tr>
<tr>
<!-- Will hide --> <td></td>
</tr>
</table>
With native Javascript:
function removeRow(src) {
var tableRows = document.getElementById(src).querySelectorAll('tr');
tableRows.forEach(function(row){
if((/^\s*$/).test(row.innerText)){
row.parentNode.removeChild(row);
}
});
}
removeRow('myTable');
The only problem is when you have some other characters in the row, except the whitespaces. This regex checks for blank characters, but if u have a dot inside or any other non empty character, it will fail.

universal javascript selector to interact on all html element

I started on that http://jsfiddle.net/DRFBG/
And if I add tables so mytable1, mytable2,...
<table id="mytable1" border="1">
<tr><th>Column1</th><th>Column2</th><th>Column3</th><th>Column4</th></tr>
<tr class="data"><td>1st</td><td>1.1</td><td></td><td>1</td></tr>
<tr class="data"><td>2nd</td><td>2.01</td><td></td><td>2</td></tr>
<tr class="data"><td>3rd</td><td>3.001</td><td></td><td>3</td></tr>
<tr class="data"><td>4th</td><td>4.01</td><td></td><td>4</td></tr>
</table>
<table id="mytable2" border="1">
<tr><th>Column1</th><th>Column2</th><th>Column3</th><th>Column4</th></tr>
<tr class="data"><td>1st</td><td>1.1</td><td>1</td><td></td></tr>
<tr class="data"><td>2nd</td><td>2.01</td><td>2</td><td></td></tr>
<tr class="data"><td>3rd</td><td>3.001</td><td>3</td><td></td></tr>
<tr class="data"><td>4th</td><td>4.01</td><td>4</td><td></td></tr>
</table>
How could I uniform my javascript code for all tables?
I've already tried passing by table[div^=mytable]*, but the problem is the second selector in the function.
So any ideas please? Thank you? Sorry for my english
By the way, the code is to remove th with empty td for each table
$('#mytable2 th').each(function(i) {
var remove = 0;
var tds = $(this).parents('table').find('tr td:nth-child(' + (i + 1) + ')')
tds.each(function(j) { if (this.innerHTML == '') remove++; });
if (remove == ($('#mytable2 tr').length - 1)) {
$(this).hide();
tds.hide();
}
});
One approach is, selecting tables first and get their id and after that, doing the approach of http://jsfiddle.net/DRFBG/ on each of them like the following:
$('table').each(function()
{
var tb_id = $(this).attr('id');
$('#'+tb_id+' th').each(function(i) {
var remove = 0;
var tds = $(this).parents('table').find('tr td:nth-child(' + (i + 1) + ')')
tds.each(function(j) { if (this.innerHTML == '') remove++; });
if (remove == ($('#'+tb_id+' tr').length - 1)) {
$(this).hide();
tds.hide();
}
});
});
Here is the working jsfiddle
To select all on your page you can use "table" selector.
So you'd need to use $('table2 th') instead of $('#mytable2 th')
One possible solution would be to loop through each column of each table, then check if there are any non-empty cells. If there is not, then you can safely remove() all the td and th within that column.
Note that the removal needs to be done last, otherwise it will affect the indexing of the following columns. You can do that by simply marking the cells to be removed with a class, and then selecting that class once all loops complete. Try this:
$('table').each(function() {
var $table = $(this);
var rows = $table.find('tr').length - 1; // -1 to account for the headings
$table.find('th').each(function(i, th) {
var $empty = $table.find(`td:nth-child(${i + 1}):empty`);
if ($empty.length == rows)
$empty.add(this).addClass('to-remove');
})
$table.find('.to-remove').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="mytable1" border="1">
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
<th>Column4</th>
</tr>
<tr class="data">
<td>1st</td>
<td>1.1</td>
<td></td>
<td>1</td>
</tr>
<tr class="data">
<td>2nd</td>
<td>2.01</td>
<td></td>
<td>2</td>
</tr>
<tr class="data">
<td>3rd</td>
<td>3.001</td>
<td></td>
<td>3</td>
</tr>
<tr class="data">
<td>4th</td>
<td>4.01</td>
<td></td>
<td>4</td>
</tr>
</table>
<table id="mytable2" border="1">
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
<th>Column4</th>
</tr>
<tr class="data">
<td>1st</td>
<td>1.1</td>
<td>1</td>
<td></td>
</tr>
<tr class="data">
<td>2nd</td>
<td>2.01</td>
<td>2</td>
<td></td>
</tr>
<tr class="data">
<td>3rd</td>
<td>3.001</td>
<td>3</td>
<td></td>
</tr>
<tr class="data">
<td>4th</td>
<td>4.01</td>
<td>4</td>
<td></td>
</tr>
</table>

How to fetch specific columns in a row and transfer it to another table

I would like to transfer a particular column only. Please help me.
Here is my code:
btnAdd.on('click', function () {
var trItem = $(this).closest("tr").clone();
trItem.find("input").remove();
trItem.add("<tr>").append("</tr>");
$("#products").append(trItem);
console.log(btnAdd);
})
thank you so much.
You need to specify all cells need to be cloned.
Function "funcCloneRow" will clone a row (tr) and add cell's content by "tdKeyArr".
Remember that "tdKeyArr" is an array contain choosen cells's position, like this:
$(function() {
var funcCloneRow = function($table1, $table2, trIndex, tdKeyArr) {
// define. If tdKeyArr == undefinded, all the cell in choosen tr will be cloned
if($table1 == undefined || $table2 == undefined || trIndex == undefined) {
return;
}
// clone row
var $tr = $table1.find('tr').eq(trIndex).clone();
// get cell content
if(tdKeyArr != undefined) {
$tr.children('td').text('');
for (var i = 0; i < tdKeyArr.length; i++) {
$tr.children('td').eq(tdKeyArr[i]).html($table1.find('tr').eq(trIndex).children('td').eq(tdKeyArr[i]).html());
}
}
// append new row to second table
if ($table2.children('tbody').length) {
$table2.children('tbody').append($tr);
}
else {
$table2.append($tr);
}
}
$('table button').on('click', function(event) {
funcCloneRow($('#table1'), $('#table2'), $(this).closest('tr').index(), [$(this).parent().index(), 1]);
});
});
table {
float:left;
margin-right:100px;
border-collapse:collapse;
text-align:center;
vertical-align:top;
}
table th,
table td {
border:1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<body>
<table id="table1">
<tr>
<th>head 1</th>
<th>head 2</th>
<th>head 3</th>
</tr>
<tr>
<td>row 1</td>
<td>row 1</td>
<td><button>Append</button></td>
</tr>
<tr>
<td>row 2</td>
<td>row 2</td>
<td><button>Append</button></td>
</tr>
<tr>
<td>row 3</td>
<td>row 3</td>
<td><button>Append</button></td>
</tr>
</table>
<table id="table2">
<tr>
<th>head 1</th>
<th>head 2</th>
<th>head 3</th>
</tr>
</table>
</body>

JS Sortable Tables with linked rows?

Okay, I have a table. In this table I have a whole bunch of columns, and I would like to use a Sortable Tables javascript so that the user can sort the table as they wish. There are many such JS scripts available (ie: http://tablesorter.com/docs/)
However, the problem I have is that for each row of my table that I want sorted, there is a colspan="4" row right below it that I dont want sorted. In fact, I want these rows linked directly to the row above them so that when those rows get sorted, the 4-span row below it sticks with it.
Is something like this possible?
table {
border: 1px black solid;
width: 100%;
}
thead {
background-color: lightgrey;
text-align: left;
}
.notes {
text-align: right;
}
<table>
<thead>
<tr>
<th>Command</th>
<th>DMG</th>
<th>EXE</th>
<th>TOT</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jouho Touken</td>
<td>19</td>
<td>17</td>
<td>42</td>
</tr>
<tr>
<td colspan="4" class="notes">Opponent crouching (H: Stagger)</td>
</tr>
<tr>
<td>Chouyoushu</td>
<td>25</td>
<td>18</td>
<td>46</td>
</tr>
<tr>
<td colspan="4" class="notes">Damage varies due to distance (25-40)</td>
</tr>
<tr>
<td>Tetsuzankou</td>
<td>40</td>
<td>19</td>
<td>75</td>
</tr>
<tr>
<td colspan="4" class="notes">Super Replay; Damage varies due to distance: 40-80</td>
</tr>
</tbody>
</table>
Here is an example of how you could do this.
Make an array of all rows in the <tbody>.
Group it into pairs. [{data, note}, ...]
Sort by a given sorting function
Flatten back into an array of table rows.
empty the <tbody> tag
Insert into the <tbody> tag everything in the sorted table rows array.
var tableBody = document.querySelector('tbody')
var tableRows = Array
.from(document.querySelectorAll('tbody > tr'))
var notesAndData = []
/* Group elements into
[
{data: <tr>, note: <tr>},
...
]
*/
for(var i = 1; i < tableRows.length; i += 2) {
notesAndData.push({
data: tableRows[i-1],
note: tableRows[i]
})
}
function flatten(arr) {
return arr.reduce(function(acc, curr) {
acc.push(curr.data)
acc.push(curr.note)
return acc
}, [])
}
function repopulateTable(arr) {
tableBody.innerHTML = ''
arr.forEach(function(element) {
tableBody.appendChild(element)
})
}
function sortTable(sortingFunc) {
/* Spread the notesAndData into a new array in
order to not modify it. This syntax is es6 */
var sorted = [...notesAndData].sort(sortingFunc)
repopulateTable(flatten(sorted))
}
function sortByDmg(ascending) {
return function(a, b) {
var aDmg = parseInt(a.data.children[1].textContent)
var bDmg = parseInt(b.data.children[1].textContent)
if (aDmg < bDmg) return ascending ? 1 : -1
return ascending ? 1 : -1
}
}
document
.querySelector('.dmgSort')
.addEventListener('click', function() {
sortTable(sortByDmg(true))
})
table {
border: 1px black solid;
width: 100%;
}
thead {
background-color: lightgrey;
text-align: left;
}
.notes {
text-align: right;
}
<button class="dmgSort">Sort By DMG Ascending</button>
<table>
<thead>
<tr>
<th>Command</th>
<th>DMG</th>
<th>EXE</th>
<th>TOT</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jouho Touken</td>
<td>19</td>
<td>17</td>
<td>42</td>
</tr>
<tr>
<td colspan="4" class="notes">Opponent crouching (H: Stagger)</td>
</tr>
<tr>
<td>Chouyoushu</td>
<td>25</td>
<td>18</td>
<td>46</td>
</tr>
<tr>
<td colspan="4" class="notes">Damage varies due to distance (25-40)</td>
</tr>
<tr>
<td>Tetsuzankou</td>
<td>40</td>
<td>19</td>
<td>75</td>
</tr>
<tr>
<td colspan="4" class="notes">Super Replay; Damage varies due to distance: 40-80</td>
</tr>
</tbody>
</table>

Highlighting a Table

So I'm trying to figure out the best and easiest way to highlight a selection of cells from a table.
#A1lnk, #B1lnk {cursor: pointer;}
<table border="1">
<tr>
<th colspan="2"><a id='A1lnk'>A1</a></th><th colspan="2"><a id='B1lnk'>B1</a></th>
</tr>
<tr>
<td>A1-1</td><td>A1-2</td><td>B1-1</td><td>B1-2</td>
</tr>
<tr>
<td>A1-3</td><td>A1-4</td><td>B1-3</td><td>B1-4</td>
</tr>
<tr>
<td>A1-5</td><td>A1-6</td><td>B1-5</td><td>B1-6</td>
</tr>
<tr>
<th colspan="2"><a id='C1lnk'>C1</a></th><th colspan="2"><a id='D1lnk'>D1</a></th>
</tr>
<tr>
<td>C1-1</td><td>C1-2</td><td>D1-1</td><td>D1-2</td>
</tr>
<tr>
<td>C1-3</td><td>C1-4</td><td>D1-3</td><td>D1-4</td>
</tr>
<tr>
<td>C1-5</td><td>C1-6</td><td>D1-5</td><td>D1-6</td>
</tr>
<tr>
<th colspan="2"><a id='E1lnk'>E1</a></th><th colspan="2"><a id='F1lnk'>F1</a></th>
</tr>
<tr>
<td>E1-1</td><td>E1-2</td><td>F1-1</td><td>F1-2</td>
</tr>
<tr>
<td>E1-3</td><td>E1-4</td><td>F1-3</td><td>F1-4</td>
</tr>
<tr>
<td>E1-5</td><td>E1-6</td><td>F1-5</td><td>F1-6</td>
</tr>
</table>
You can see I have essentially got two columns, A1 and B1. The contents are very simple but suffice to say the actual contents will not be that simple.
I want to be able to click B1 and all the cells below it are highlighted, highlights are the easy part, actually selecting the correct cells is much harder.
I will have multiple other small tables adding C1, D1, E1, F1, G1, H1 etc. So there could be a few extra but only ever in columns of two. They will cascade in the rows and so still be part of the parent table but I'm just trying to figure out the best way to go about it, since the table creates them in rows and not columns.
I tried something like you said, however the code gone very long, that's why I have removed some rows.
var a1lnk = document.getElementById('A1lnk');
var a2lnk = document.getElementById('B1lnk');
var a3lnk = document.getElementById('C1lnk');
var a1 = document.getElementById('a1');
var a2 = document.getElementById('a2');
var c1 = document.getElementById('c1');
var c2 = document.getElementById('c2');
function unhighlight () {
b1.removeAttribute('h');
b2.removeAttribute('h');
a1.removeAttribute('h');
a2.removeAttribute('h');
c1.removeAttribute('h');
c2.removeAttribute('h');
}
var b1 = document.getElementById('b1');
var b2 = document.getElementById('b2');
function highlightA () {
unhighlight();
a1.setAttribute('h', true);
a2.setAttribute('h', true);
}
function highlightB () {
unhighlight();
b1.setAttribute('h', true);
b2.setAttribute('h', true);
}
function highlightC () {
unhighlight();
c1.setAttribute('h', true);
c2.setAttribute('h', true);
}
a1lnk.onclick = highlightA;
a2lnk.onclick = highlightB;
a3lnk.onclick = highlightC;
#A1lnk, #B1lnk, #C1lnk {cursor: pointer;}
td[h] {
background-color: orange;
color: #fff;
}
<table border="1">
<tr>
<th colspan="2"><a id='A1lnk'>A1</a></th><th colspan="2"><a id='B1lnk'>B1</a></th>
</tr>
<tr>
<td id="a1">A1-1</td><td id="a2">A1-2</td><td id="b1">B1-1</td><td id="b2">B1-2</td>
</tr>
<tr>
<th colspan="2"><a id='C1lnk'>C1</a></th>
</tr>
<tr>
<td id="c1">C1-1</td><td id="c2">C1-2</td>
</tr>
</table>
Hope, this should work for you.
You should use a class for header instead of different ids. Then on click of header get it's index. Using this index you can easily select the cells below it using nextUntil() method and :nth-child pseudo selector and highlight them like following.
$('.header').click(function() {
var index = $(this).parent().index(),
a = index * 2 + 1,
b = a + 1;
$('.highlight').removeClass('highlight');
var tr = $(this).closest('tr').nextUntil(':has(th)')
tr.find('td:nth-child(' + a + '), td:nth-child(' + b + ')').addClass('highlight');
});
.header {
cursor: pointer;
}
.highlight {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr>
<th colspan="2"><a class="header">A1</a></th>
<th colspan="2"><a class="header">B1</a></th>
</tr>
<tr>
<td>A1-1</td>
<td>A1-2</td>
<td>B1-1</td>
<td>B1-2</td>
</tr>
<tr>
<td>A1-3</td>
<td>A1-4</td>
<td>B1-3</td>
<td>B1-4</td>
</tr>
<tr>
<td>A1-5</td>
<td>A1-6</td>
<td>B1-5</td>
<td>B1-6</td>
</tr>
<tr>
<th colspan="2"><a class="header">C1</a></th>
<th colspan="2"><a class="header">D1</a></th>
</tr>
<tr>
<td>C1-1</td>
<td>C1-2</td>
<td>D1-1</td>
<td>D1-2</td>
</tr>
<tr>
<td>C1-3</td>
<td>C1-4</td>
<td>D1-3</td>
<td>D1-4</td>
</tr>
<tr>
<td>C1-5</td>
<td>C1-6</td>
<td>D1-5</td>
<td>D1-6</td>
</tr>
<tr>
<th colspan="2"><a class="header">E1</a></th>
<th colspan="2"><a class="header">F1</a></th>
</tr>
<tr>
<td>E1-1</td>
<td>E1-2</td>
<td>F1-1</td>
<td>F1-2</td>
</tr>
<tr>
<td>E1-3</td>
<td>E1-4</td>
<td>F1-3</td>
<td>F1-4</td>
</tr>
<tr>
<td>E1-5</td>
<td>E1-6</td>
<td>F1-5</td>
<td>F1-6</td>
</tr>
</table>

Categories