Javascript highest number in each tr, skip 3 columns - javascript

I have a table, that will add a class to the highest number in each tr.
I want it to skip the first 3 columns and not search them. And then if there are multiple of the highest then bold those too.
I will paste code here as well as fiddle.
HTML
<style>
.highest {
font-weight: bold;
}
</style>
<table width="300">
<tr>
<th>no</th>
<th>no</th>
<th>no</th>
<th>yes</th>
<th>yes</th>
<th>yes</th>
</tr>
<tr>
<td>150</td>
<td>name</td>
<td>10.5</td>
<td>1.5</td>
<td>12</td>
<td>9.3</td>
</tr>
<tr>
<td>12.0</td>
<td>name</td>
<td>150</td>
<td>150</td>
<td>13.5</td>
<td>150</td>
</tr>
<tr>
<td>160</td>
<td>name</td>
<td>115</td>
<td>15</td>
<td>11</td>
<td>160</td>
</tr>
<tr>
<td>145</td>
<td>name</td>
<td>151</td>
<td>12</td>
<td>18</td>
<td>18</td>
</tr>
</table>
JAVASCRIPT
jQuery(function($) {
$.fn.max = function(callback) {
var max = null,
maxIndex = null;
this.each(function() {
var value = callback.call(this);
if (+value === value) {
if (!max || value > max) {
max = value;
maxIndex = $(this).index();
}
}
});
return max !== null ? this.eq(maxIndex) : $();
};
}(jQuery));
$('tr').each(function()
$(this).children('td').max(function() {
var value = +$(this).text();
if (!isNaN(value)) {
return value;
}
}).addClass('highest');
});
FIDDLE
http://jsfiddle.net/65S7N/96/

Just add a selector as a parameter to the plugin, and filter by that :
jQuery(function($) {
$.fn.max = function(selector) {
var elems = $();
this.each(function() {
var max = 0,
ele = $(this).find(selector).each(function(i,el) {
var n = parseFloat($(el).text());
if ( n > max ) max = n;
}).filter(function() {
return parseFloat($(this).text()) === max;
});
elems = elems.add(ele);
});
return elems;
};
}(jQuery));
$('tr').max('td:gt(2)').addClass('highest');
FIDDLE

To skip the first 3 columns, use:
$(this).children('td').filter(function(i) {
return i > 2;
}).max(...)
The filter function receives the zero-based position of the element within the collection.
If you want to highlight multiple entries that have the max value, maxIndex needs to be an array, not a single value. When value === max, push the current index onto the array. Or make it a jQuery collection of elements, rather than indexes, and add the current element to it.

$('tr').each(function(){
var this = $(this);
var max = -Infinity;
var indexes = [];
this.find('td:gt(2)').each(function(index){
var this_num = ($(this).text() >> 0);
if ( max < this_num ) {
max = this_num;
indexes = [index];
} else if (max == this_num ) {
indexes.push(this_num);
}
});
$(indexes).each(function(index){
this.find('td:eq('+index+')').addClass('highest');
});
});
should work.. haven't tested :|

Related

How to sort table by date column

I have a table and I want to sort Date column ascending and descending.
I have tried the code below but its not working. Its work when sorting the numbers only.
function sortColumn() {
var table, rows, switching, i, x, y, shouldSwitch;
table = document.getElementById("example");
switching = true;
while (switching) {
switching = false;
rows = table.rows;
for (i = 1; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("TD")[6];
y = rows[i + 1].getElementsByTagName("TD")[6];
if (parseInt(x.innerHTML.toLowerCase()) > parseInt(y.innerHTML.toLowerCase())) {
shouldSwitch = true;
break;
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
}
}
}
Here is a more complex example than you might have been looking for. It makes use of the Array Sort function, which can make use of an optional compareFunction to perform the sort comparison.
$(function() {
function tableToArray(tObj) {
var result = [];
var keys = [];
$("thead th", tObj).each(function(i, el) {
keys.push($(el).text().trim());
});
$("tbody tr").each(function(i, row) {
var temp = {};
$.each(keys, function(j, k) {
temp[k] = $("td", row).eq(j).text().trim();
});
result.push(temp);
});
return result;
}
function replaceTableData(tObj, data) {
var b = $("tbody", tObj);
b.html("");
$.each(data, function(i, row) {
var r = $("<tr>").appendTo(b);
$.each(row, function(j, cell) {
$("<td>").html(cell).appendTo(r);
});
});
}
function compare(a, b) {
var dateA = a.Date;
var dateB = b.Date;
var result = 0;
if (dateA > dateB) {
result = 1;
} else {
result = -1;
}
return result;
}
function sortTable() {
var tData = tableToArray($("table"));
tData.sort(compare);
replaceTableData($("table"), tData);
}
$(".sort-column").click(sortTable);
});
.sort-column {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>ID</th>
<th class="sort-column" data-sort-order="null">Date</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>17/12/1989</td>
<td>Homer</td>
</tr>
<tr>
<td>2</td>
<td>07/09/2019</td>
<td>Marge</td>
</tr>
<tr>
<td>3</td>
<td>01/09/2019</td>
<td>Bart</td>
</tr>
<tr>
<td>4</td>
<td>04/09/2019</td>
<td>Lisa</td>
</tr>
<tr>
<td>5</td>
<td>14/09/2019</td>
<td>Maggie</td>
</tr>
</tbody>
</table>
This sorts based on the text in the Date column. You could get more complex and parse the Date into a Date Object when you compare. But with this date format, it's not really needed.
Update
Moved code into function so it can be called in a Click event. This is a really simple example and if you need more complex actions, consider how that might work or DataTables.

Wrong array method sort() logic

I Cannot understand the array method sort() logic. I had to write an eventListener for the two elements Age and Letter. By clicking on them we can sort our table by age and letter.
All works fine, but I see something strange in the sort() logic. By clicking on the Letter - table must sort by alphabet for elements in the column Letter. By clicking on the Age - table must sort by digits order for elements in the column Age. But it does not sort right.
tbody = document.getElementById('grid');
function tableSort(event) {
var target = event.target;
var action = target.getAttribute('data-type');
var arr = [].slice.call(grid.rows, 1);
var self = this;
this.number = function() {
arr.sort(function(a, b) { // sort by digits in the column "Age"
a.cells[0].innerHTML;
b.cells[0].innerHTML;
return a - b;
});
grid.appendChild(...arr);
}
this.string = function() {
arr.sort(function(a, b) { // sort by words in the column "Letter"
a.cells[1].innerHTML;
b.cells[1].innerHTML;
return a > b;
});
grid.appendChild(...arr);
}
if (action) {
self[action]();
}
}
tbody.addEventListener('click', tableSort);
th {
cursor: pointer;
}
<table id="grid">
<thead>
<tr>
<th data-type="number">Age</th>
<th data-type="string">Letter</th>
</tr>
</thead>
<tbody>
<tr>
<td>5</td>
<td>BBBBB</td>
</tr>
<tr>
<td>12</td>
<td>AAAAA</td>
</tr>
<tr>
<td>1</td>
<td>DDDDD</td>
</tr>
<tr>
<td>9</td>
<td>CCCCC</td>
</tr>
<tr>
<td>2</td>
<td>KKKKK</td>
</tr>
</tbody>
</table>
<script>
</script>
Modified your code and got it working. Here if you need it:
function tableSort(event) {
var target = event.target;
var action = target.getAttribute("data-type");
var arr = [].slice.call(grid.rows, 1);
var self = this;
this.number = function() {
arr.sort(function(a, b) {
// sort by digits in the column "Age"
return Number(a.cells[0].innerHTML) - Number(b.cells[0].innerHTML);
});
arr.forEach(function(item, index) {
grid.appendChild(item);
});
};
this.string = function() {
arr.sort(function(a, b) {
// sort by words in the column "Letter"
var str1 = a.cells[1].innerHTML;
var str2 = b.cells[1].innerHTML;
return str1.localeCompare(str2);
});
arr.forEach(function(item, index) {
grid.appendChild(item);
});
};
if (action) {
self[action]();
}
}
tbody.addEventListener("click", tableSort);
How about this stackoverflow post Sorting HTML table with JavaScript for clarification and the original external article in which I found it with a full example?
Sorting tables with VanillaJS or JQuery
Example:
/**
* Modified and more readable version of the answer by Paul S. to sort a table with ASC and DESC order
* with the <thead> and <tbody> structure easily.
*
* https://stackoverflow.com/a/14268260/4241030
*/
var TableSorter = {
makeSortable: function(table){
// Store context of this in the object
var _this = this;
var th = table.tHead, i;
th && (th = th.rows[0]) && (th = th.cells);
if (th){
i = th.length;
}else{
return; // if no `<thead>` then do nothing
}
// Loop through every <th> inside the header
while (--i >= 0) (function (i) {
var dir = 1;
// Append click listener to sort
th[i].addEventListener('click', function () {
_this._sort(table, i, (dir = 1 - dir));
});
}(i));
},
_sort: function (table, col, reverse) {
var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows
tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array
i;
reverse = -((+reverse) || -1);
// Sort rows
tr = tr.sort(function (a, b) {
// `-1 *` if want opposite order
return reverse * (
// Using `.textContent.trim()` for test
a.cells[col].textContent.trim().localeCompare(
b.cells[col].textContent.trim()
)
);
});
for(i = 0; i < tr.length; ++i){
// Append rows in new order
tb.appendChild(tr[i]);
}
}
};
window.onload = function(){
TableSorter.makeSortable(document.getElementById("myTable"));
};
table thead th {
cursor: pointer;
}
<table id="myTable">
<thead>
<th data-type="string">Name</th>
<th data-type="number">Age</th>
</thead>
<tbody>
<tr>
<td>John</td>
<td>42</td>
</tr>
<tr>
<td>Laura</td>
<td>39</td>
</tr>
<tr>
<td>Fred</td>
<td>18</td>
</tr>
<tr>
<td>Bod</td>
<td>26</td>
</tr>
</tbody>
</table>

get the sum of 2nd column in html table

input : <table> <tr> <td>100</td> </tr> <tr> <td>200</td> </tr> </table> from the input it should return me the sum=300 instead I'm getting the output as 100200
function Save_Name()
{
var Invoice = $("#text_invoice").val();
var Name = $("#text_name").val();
var Date = $("#text_date").val();
var Amount = 0;
var n = $("table").find("tr").length;
if (n - 1 > 0)
{
for (var i = 0 ; i < n; i++)
{
var Amt = $("#table1").find("tr").eq(i).find("td").eq(2).text();
Amount += parseFloat(Amt);
}
}
}
eq starts with 0 index.The output 100200 is because it is concatenating the string instead of adding the values.Also use parseInt to convert the number from string to integer.
function Save_Name() {
var Amount = 0;
// will get all tr
var n = $("#table1 tr");
n.each(function(i, v) {
// table have only one td per tr so eq(0) will give first td
// trim is used to remove any white space
Amount += parseInt($(v).eq(0).text().trim(), 10)
})
console.log(Amount)
}
Save_Name()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table1">
<tr>
<td>100</td>
</tr>
<tr>
<td>200</td>
</tr>
</table>
Here's another way to do the same thing. Basically, I use map to create a map of integer values, then I use "get" to convert them into an array, and finally I use reduce to calculate the sum of the values in the array.
P.S.: To calculate the second column, all you need to do is to use nth-child(2) instead of nth-child(1).
$(function(){
var sum = $('#table1 tr td:nth-child(1)').map(function() {
return parseInt($(this).html(), 10)
}).get().reduce(function(a, v){
return a + v;
}, 0);
console.log(sum);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table id="table1">
<tr>
<td>100</td>
</tr>
<tr>
<td>200</td>
</tr>
</table>
I have alert the value of sum Amount and it is equal to 300 .
You were doing some mistake as eq(2) instead of eq(0)
But Here's the working snippet:
function Save_Name()
{
var Amount = 0;
var n = $('#test tr').length;
// alert(n);
if (n - 1 > 0)
{
for (var i = 0 ; i < n; i++)
{
var Amt = $("#test").find("tr").eq(i).find("td").eq(0).text();
Amount += parseFloat(Amt);
}
alert(Amount);
}
}
Save_Name();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id='test'>
<tr> <td>100 </td></tr>
<tr> <td>200 </td></tr>
</table>

Sum column totals depending on text of another column using jQuery

I have this code that I use to calculate totals in specific columns based on the text in a different column. It works just fine, but I'm learning, so I would like to know if there is way to consolidate this code. As you can see I run a "each()" twice, once for each column. The first each check for "A" in the first column, then goes to the second column and adds the rows that meet the criteria. Similar on the second column, just that it looks for "B" and add columns 3. Is there a way to run the each function only once and check both column at the same time?
JS:
//Second Column
var total = 0;
$("#theTable tr:contains('A') td:nth-of-type(2)").each(function () {
var pending = parseInt($(this).text());
total += pending;
});
$("#theTable tfoot tr:last-of-type td:nth-of-type(2)").text(total);
//Third Column
var total2 = 0;
$("#theTable tr:contains('B') td:nth-of-type(3)").each(function () {
var pending2 = parseInt($(this).text());
total2 += pending2;
});
$("#theTable tfoot tr:last-of-type td:nth-of-type(3)").text(total2);
HTML:
<table id="theTable">
<thead>
<tr>
<th>MONTH</th>
<th>PENDING</th>
<th>DENIED</th>
</tr>
</thead>
<tbody></tbody>
<tr>
<td>A</td>
<td>2</td>
<td>4</td>
</tr>
<tr>
<td>B</td>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>3</td>
<td>2</td>
</tr>
<tr>
<td>C</td>
<td>3</td>
<td>2</td>
</tr>
<tr>
<td>A</td>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>B</td>
<td>4</td>
<td>2</td>
</tr>
<tfoot>
<tr>
<td>TOTALS:</td>
<td></td>
<td></td>
</tr>
</tfoot>
This may look simple for some of you, but again, I'm just learning some JS now.
Thanks!
You could try something like this:
var total = {A:{row:1,t:0},B:{row:2,t:0}};
$('#theTable tr').each(function() {
$row = $(this);
$.each(total, function(key, col) {
rowFil = $row.filter(':contains("' + key + '")');
col.t += (rowFil) ? +rowFil.find('td:eq(' + col.row + ')').text() : 0;
});
});
$("#theTable tfoot tr:last td:eq(1)").text(total.A.t);
$("#theTable tfoot tr:last td:eq(2)").text(total.B.t);
someThing of this sort might Help ...
var trs = $('#'+tblID).find('tr');
var total1 = 0;
var total2 = 0;
$.each(trs, function(k, v) {
if ($(v).text == "A"){
total1 += parseInt($(v).parent('tr').find('td:eq(2)').text());
}
if ($(v).text == "B"){
total2 += parseInt($(v).parent('tr').find('td:eq(3)').text())
}
});
Here is another approach - I've summed up all statistics for all possible values:
var totals = [];
$('#theTable tbody tr').each(function(e) {
var tds= $(this).find('td');
var index = $(tds[0]).text();
var pending = parseInt($(tds[1]).text(), 10);
var denied = parseInt($(tds[2]).text(), 10);
if (totals[index] == undefined)
totals[index] = { Pending: 0, Denied: 0 };
totals[index].Pending += pending;
totals[index].Denied += denied;
});
for (var key in totals)
$('#theTable tfoot').append('<tr><td>'+key+'</td><td>'+
totals[key].Pending+'</td><td>'+totals[key].Denied+'</td></tr>');
I've also updated markup a little, here is jsfiddle. The code may be not so pretty, but doing more stuff and can be refactored.
Creating a second table with the sums makes it easier to analyse the data.
SOLUTION
JS
//make a list of unique months
var months = [];
$('#theTable tr td:nth-of-type(1)').each(function(){
var month = $(this).text();
if(months.indexOf(month) < 0) months.push(month);
});
console.log('months', months);
//make a data structure with sums
var data = {};
var tr = $('#theTable tr');
$.each(months, function(){
var month = this;
data[month] = {
pending: 0,
denied: 0
};
tr.each(function(){
var ch = $(this).children();
var m = $(ch[0]).text();
var pending = $(ch[1]).text();
var denied = $(ch[2]).text();
if(m == month) {
data[month].pending += parseInt(pending);
data[month].denied += parseInt(denied);
}
});
});
console.log('data', data);
//make a table with the data
var table = $('<table>');
table.append($('<tr>'+
'<th>MONTH</th>'+
'<th>PENDING</th>'+
'<th>DENIED</th>'+
'</tr>'));
$.each(data, function(month){
table.append($('<tr>'+
'<td>'+month+'</td>'+
'<td>'+data[month].pending+'</td>'+
'<td>'+data[month].denied+'</td>'+
'</tr>'));
});
$('body').append(table);

Finding column index using jQuery when table contains column-spanning cells

Using jQuery, how can I find the column index of an arbitrary table cell in the example table below, such that cells spanning multiple columns have multiple indexes?
HTML
<table>
<tbody>
<tr>
<td>One</td>
<td>Two</td>
<td id="example1">Three</td>
<td>Four</td>
<td>Five</td>
<td>Six</td>
</tr>
<tr>
<td colspan="2">One</td>
<td colspan="2">Two</td>
<td colspan="2" id="example2">Three</td>
</tr>
<tr>
<td>One</td>
<td>Two</td>
<td>Three</td>
<td>Four</td>
<td>Five</td>
<td>Six</td>
</tr>
</tbody>
</table>
jQuery
var cell = $("#example1");
var example1ColIndex = cell.parent("tr").children().index(cell);
// == 2. This is fine.
cell = $("#example2");
var example2ColumnIndex = cell.parent("tr").children().index(cell);
// == 2. It should be 4 (or 5, but I only need the lowest). How can I do this?
Here's a plugin which can calculate the 'noncolspan' index.
$(document).ready(
function()
{
console.log($('#example2').getNonColSpanIndex()); //logs 4
console.log($('#example1').getNonColSpanIndex()); //logs 2
}
);
$.fn.getNonColSpanIndex = function() {
if(! $(this).is('td') && ! $(this).is('th'))
return -1;
var allCells = this.parent('tr').children();
var normalIndex = allCells.index(this);
var nonColSpanIndex = 0;
allCells.each(
function(i, item)
{
if(i == normalIndex)
return false;
var colspan = $(this).attr('colspan');
colspan = colspan ? parseInt(colspan) : 1;
nonColSpanIndex += colspan;
}
);
return nonColSpanIndex;
};
Mine is quite similar to SolutionYogi's, minus the creation of a plugin. It took me a bit longer... but I'm still proud of it so here it is :)
cell = $("#example2");
var example2ColumnIndex2 = 0;
cell.parent("tr").children().each(function () {
if(cell.get(0) != this){
var colIncrementor = $(this).attr("colspan");
colIncrementor = colIncrementor ? colIncrementor : 1;
example2ColumnIndex2 += parseInt(colIncrementor);
}
});
console.log(example2ColumnIndex2);
There is a more concise answer here: Get Index of a td considering the colspan using jquery
In short:
var index = 0;
$("#example2").prevAll("td").each(function() {
index += this.colSpan;
});
console.log(index);
You could do something like this:
var index = 0;
cell.parent('tr').children().each(
function(idx,node) {
if ($(node).attr('colspan')) {
index+=parseInt($(node).attr('colspan'),10);
} else {
index++;
}
return !(node === cell[0]);
}
);
console.log(index);
It'd probably make sense to do it as a plugin or via extend.
Slightly modified version is here: http://jsfiddle.net/Lijo/uGKHB/13/
//INDEX
alert ( GetNonColSpanIndex ('Type'));
function GetNonColSpanIndex(referenceHeaderCellValue) {
var selectedCell = $("th").filter(function (i) {
return ($.trim($(this).html() )) == referenceHeaderCellValue;
});
alert(selectedCell.html());
var allCells = $(selectedCell).parent('tr').children();
var normalIndex = allCells.index($(selectedCell));
var nonColSpanIndex = 0;
allCells.each(
function (i, item) {
if (i == normalIndex)
return false;
var colspan = $(selectedCell).attr('colspan');
colspan = colspan ? parseInt(colspan) : 1;
nonColSpanIndex += colspan;
}
);
return nonColSpanIndex;
};
​

Categories

Resources