Using Datatables 1.10.19 and bootstrap-datepicker v1.8.0
I have two columns in my table, one contains a cash value, the other contains payment type (cash / card). What I need to do is calculate the totals for each payment type whenever the data is filtered via the datepicker.
So, when a date range is selected I need to display;
Total Cash: £x
Total Card £x
I'm already able to calculate the totals within the table, and when it's filtered via the search input, but i'm stuck on the datepicker.
I have created a fiddle here. Code is below;
html
<div class="container">
<div class="col-md-4 pull-right">
<div class="input-group input-daterange">
<input class="form-control date-range-filter" data-date-format="dd-mm-yyyy" id="min-date" placeholder="From:" type="text">
<div class="input-group-addon">
to
</div><input class="form-control date-range-filter" data-date-format="dd-mm-yyyy" id="max-date" placeholder="To:" type="text">
</div>
</div>
</div>
<hr>
<p>Overall Totals: <span id="overallTotals"></span></p>
<p>Filtered Totals: <span id="filteredTotals"></span></p>
<hr>
<table class="table table-striped table-bordered" id="records" style="width:100%">
<thead>
<tr>
<th>Date Paid</th>
<th>Invoice</th>
<th>Amount</th>
<th>Charge Type</th>
<th>Payment Type</th>
</tr>
</thead>
<tfoot>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</tfoot>
<tbody>
<tr class="odd" role="row">
<td class="sorting_1">27-03-2019</td>
<td>521735</td>
<td>0.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">27-03-2019</td>
<td>513938</td>
<td>1.20</td>
<td>overdue</td>
<td>Cash</td>
</tr>
<tr class="odd" role="row">
<td class="sorting_1">27-03-2019</td>
<td>523693</td>
<td>0.20</td>
<td>overdue</td>
<td>Cash</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">27-03-2019</td>
<td>493645</td>
<td>0.10</td>
<td>overdue renewed</td>
<td>Cash</td>
</tr>
<tr class="odd" role="row">
<td class="sorting_1">27-03-2019</td>
<td>521734</td>
<td>0.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">27-03-2019</td>
<td>493646</td>
<td>0.10</td>
<td>overdue renewed</td>
<td>Cash</td>
</tr>
<tr class="odd" role="row">
<td class="sorting_1">27-03-2019</td>
<td>523691</td>
<td>0.10</td>
<td>overdue renewed</td>
<td>Card</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">27-03-2019</td>
<td>523692</td>
<td>0.10</td>
<td>overdue renewed</td>
<td>Card</td>
</tr>
<tr class="odd" role="row">
<td class="sorting_1">27-03-2019</td>
<td>523694</td>
<td>0.20</td>
<td>overdue</td>
<td>Cash</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">26-03-2019</td>
<td>506326</td>
<td>1.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">26-03-2019</td>
<td>506322</td>
<td>1.60</td>
<td>overdue</td>
<td>Card</td>
</tr>
<tr class="even" role="row">
<td class="sorting_1">25-03-2019</td>
<td>506399</td>
<td>5.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
</tbody>
</table>
js
$(document).ready(function() {
// Bootstrap datepicker
$('.input-daterange input').each(function() {
$(this).datepicker('clearDates');
});
var table = $('#records').DataTable({
"order": [
[0, "desc"]
],
"columns": [{
data: 'datePaid',
}, {
data: 'invoice',
}, {
data: 'amount',
"render": function(data, type, row) {
return '£' + Number(data).toFixed(2);
},
}, {
data: 'chargeType'
}, {
data: 'paymentType'
}, ],
"columnDefs": [{
targets: [0],
type: 'date-eu'
}],
"footerCallback": function(row, data, start, end, display) {
var api = this.api(),
data;
// Remove the formatting to get integer data for summation
var intVal = function(i) {
return typeof i === 'string' ? i.replace(/[\$,]/g, '') * 1 : typeof i === 'number' ? i : 0;
};
// find column named Amount
var costColumnIndex = $('th').filter(function(i) {
return $(this).text() == 'Amount';
}).first().index();
// array of total column values
var totalData = api.column(costColumnIndex).data();
// total of column values
var total = totalData.reduce(function(a, b) {
return intVal(a) + intVal(b);
}, 0).toFixed(2);
// array of displayed column values
var pageTotalData = api.column(costColumnIndex, {
page: 'current'
}).data();
// total of displayed values
var pageTotal = pageTotalData.reduce(function(a, b) {
return intVal(a) + intVal(b);
}, 0).toFixed(2);
// array of displayed column values
var searchTotalData = api.column(costColumnIndex, {
'filter': 'applied'
}).data();
// total of displayed values
var searchTotal = searchTotalData.reduce(function(a, b) {
return intVal(a) + intVal(b);
}, 0).toFixed(2);
// console.log(searchTotal);
$('#overallTotals').html('Approximate page total £' + pageTotal + ', search total £' + searchTotal + ', totally total $' + total);
$('#filteredTotals').html('Cash total £' + 'x' + ', Card total £' + 'x');
$(api.column(2).footer()).html('£' + Number(pageTotal).toFixed(2));
},
});
// Extend dataTables search
$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
var min = $('#min-date').val();
var max = $('#max-date').val();
var createdAt = data[0] || 0; // Our date column in the table
createdAt = moment(createdAt, "DD-MM-YYYY").format('MM/DD/YYYY');
min = min ? moment(min, "DD-MM-YYYY").format('MM/DD/YYYY') : "";
max = max ? moment(max, "DD-MM-YYYY").format('MM/DD/YYYY') : "";
if (
(min == "" || max == "") || (moment(createdAt).isSameOrAfter(min) && moment(createdAt).isSameOrBefore(max))) {
return true;
}
return false;
});
// Re-draw the table when the a date range filter changes
$('.date-range-filter').change(function() {
$('#records').DataTable().draw();
});
});
Any help is appreciated.
Related
I'm trying to sort rows in alphabetical order based on which column header is clicked using jQuery. It works fairly fine when debugging except that it doesn't actually switch the rows in the HTML and so it doesn't display a sorted table on the webpage. I'm using Thymeleaf th:text to populate the table body rows but for the sake of this example, I hardcoded some values. You can run it here: https://jsfiddle.net/tg2khrd4
Javascript:
var table = $("#table");
$("#subject, #from, #id")
.wrapInner('<span title="sort this column"/>')
.each(function () {
var th = $(this),
thIndex = th.index(),
inverse = false;
th.click(function () {
table
.find("tbody")
.find("td")
.filter(function () {
return $(this).index() === thIndex;
})
.sort(
function (a, b) {
return $.text([a]) > $.text([b])
? inverse
? -1
: 1
: inverse
? 1
: -1;
},
function () {
// parentNode is the element we want to move
return this.parentNode;
}
);
inverse = !inverse;
});
});
HTML:
<table class="table table-hover" id="table" style="background-color:#fff;border: 1px solid #cccccc">
<thead style="background-color:#981e32;">
<tr>
<td class="tdsubj" id="id" style="padding:5px;">Id
</td>
<td class="tdsubj" id="subject" style="padding:5px;">
Subject
</td>
<td class="tdsubj" id="from" style="padding:5px;">
From
</td>
<td class="tdsubj" id="date" style="padding:5px;">
Date
</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Hello</td>
<td>Thor</td>
<td>2020-10-19</td>
</tr>
<tr>
<td>2</td>
<td>Dinos Suck</td>
<td>Meteor</td>
<td>2020-9-5</td>
</tr>
<tr>
<td>3</td>
<td>Big Ben won't stop ringing</td>
<td>The Queen</td>
<td>2020-8-19</td>
</tr>
</tbody>
</table>
Once the td sorted... You just have to loop throught it and append it's parent tr in the table...
var table = $("#table");
$("#subject, #from, #id")
// .wrapInner('<span title="sort this column"/>')
.each(function () {
var th = $(this),
thIndex = th.index(),
inverse = false;
th.click(function () {
let test = table
.find("tbody")
.find("td")
.filter(function () {
return $(this).index() === thIndex;
})
.sort(
function (a, b) {
return $.text([a]) > $.text([b])
? inverse
? -1
: 1
: inverse
? 1
: -1;
}
// That is useless...
/*function () {
// parentNode is the element we want to move
console.log(this.parentNode)
return this.parentNode;
}*/
);
// Added to demonstrate the sorting works
console.clear()
test.each(function () {
console.log(this.innerText);
});
// Now to apply the sorting on the DOM
// Find the tr containing it and append it to the table.
test.each(function () {
table.append($(this).parent("tr"))
});
inverse = !inverse;
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table table-hover" id="table" style="background-color:#fff;border: 1px solid #cccccc">
<thead style="background-color:#981e32;">
<tr>
<td class="tdsubj" id="id" style="padding:5px;">Id
</td>
<td class="tdsubj" id="subject" style="padding:5px;">
Subject
</td>
<td class="tdsubj" id="from" style="padding:5px;">
From
</td>
<td class="tdsubj" id="date" style="padding:5px;">
Date
</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Hello</td>
<td>Thor</td>
<td>2020-10-19</td>
</tr>
<tr>
<td>2</td>
<td>Dinos Suck</td>
<td>Meteor</td>
<td>2020-9-5</td>
</tr>
<tr>
<td>3</td>
<td>Big Ben won't stop ringing</td>
<td>The Queen</td>
<td>2020-8-19</td>
</tr>
</tbody>
</table>
I am calculating some totals on page load, based on some conditions (cash / card) this work well. Now I need them to change dynamically as I search.
Searching will be performed with the default search input and a datepicker. The search seems to work fine, the changing totals doesn't.
I have most of it working and my code is below.
Any help is appreciated.
html
$(document).ready(function() {
$('.input-daterange input').each(function() {
$(this).datepicker('clearDates');
});
$('#records').DataTable({
"footerCallback": function(row, data, start, end, display) {
var api = this.api(),
data;
let cashTotalValue = 0;
let cardTotalValue = 0;
let min = $('#min-date').val() ? $('#min-date').val().split("-") : "";
let max = $('#max-date').val() ? $('#max-date').val().split("-") : "";
min = min ? new Date(min[1] + '/' + min[0] + '/' + min[2]) : "";
max = max ? new Date(max[1] + '/' + max[0] + '/' + max[2]) : "";
api.rows().eq(0).each(function(index) {
var row = api.row(index);
var createdAt = row.data().datePaid.split("-") || 0; // Our date column in the table
createdAt = new Date(createdAt[1] + '/' + createdAt[0] + '/' + createdAt[2]);
if ((min === "" || moment(createdAt).isSameOrAfter(min)) &&
(max === "" || moment(createdAt).isSameOrBefore(max))) {
// the "type" column is #5, but arrays are 0 based, so subtract one
if (row.data().paymentType == 'Cash') {
// the "amount" column is #3, but arrays are 0 based, so subtract one
let poundAmount = row.data().amount;
let amount = 0;
if (poundAmount.startsWith("£")) {
amount = parseFloat(poundAmount.substring(1));
} else {
amount = parseFloat(poundAmount);
}
// console.log(amount);
cashTotalValue += amount;
}
if (row.data().paymentType == 'Card') {
// the "amount" column is #3, but arrays are 0 based, so subtract one
let poundAmount = row.data().amount;
let amount = 0;
if (poundAmount.startsWith("£")) {
amount = parseFloat(poundAmount.substring(1));
} else {
amount = parseFloat(poundAmount);
}
// console.log(amount);
cardTotalValue += amount;
}
$('#totalCash').html('Total Cash: ' + cashTotalValue.toFixed(2));
$('#totalCard').html('Total Card: ' + cardTotalValue.toFixed(2));
}
});
/* $('#totalCash').html('Total Cash: ' + cashTotalValue.toFixed(2));
$('#totalCard').html('Total Card: ' + cardTotalValue.toFixed(2)); */
},
"order": [
[0, "desc"]
],
"columns": [{
data: 'datePaid'
},
{
data: 'invoice'
},
{
data: 'amount'
},
{
data: 'chargeType'
},
{
data: 'paymentType'
},
],
"columnDefs": [{
targets: [0],
type: 'date-eu'
}],
});
// Extend dataTables search
$.fn.dataTable.ext.search.push(
function(settings, data, dataIndex) {
var min = $('#min-date').val()? $('#min-date').val().split("-") : "";
var max = $('#max-date').val()? $('#max-date').val().split("-") : "";
var createdAt = data[0].split("-") || 0; // Our date column in the table
createdAt = new Date(createdAt[1] + '/' + createdAt[0] + '/' + createdAt[2])
min = min?new Date(min[1] + '/' + min[0] + '/' + min[2]): "";
max = max?new Date(max[1] + '/' + max[0] + '/' + max[2]):"";
if (
(min==="" || max ==="") ||
(moment(createdAt).isSameOrAfter(min) && moment(createdAt).isSameOrBefore(max))
) {
return true;
}
return false;
}
);
// Re-draw the table when the a date range filter changes
$('.date-range-filter').change(function() {
$('#records').DataTable().draw();
});
});
<link rel="stylesheet" href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudfla
re.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script src="//cdn.datatables.net/plug-ins/1.10.19/sorting/date-eu.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<div class="container">
<div class="col-md-4 pull-right">
<div class="input-group input-daterange">
<input type="text" id="min-date" class="form-control date-range-filter" data-date-format="dd-mm-yyyy" placeholder="From:">
<div class="input-group-addon">to</div>
<input type="text" id="max-date" class="form-control date-range-filter" data-date-format="dd-mm-yyyy" placeholder="To:">
</div>
</div>
</div>
<input type="button" id="btn-do-total" value="Total" />
<hr>
<p id="totalCash"></p>
<p id="totalCard"></p>
<hr>
<table id="records" class="table table-striped table-bordered" style="width:100%">
<thead>
<tr>
<th>date</th>
<th>Num</th>
<th>Price</th>
<th>Status</th>
<th>Type</th>
</tr>
</thead>
<tfoot>
<tr>
<th>date</th>
<th>Num</th>
<th>Price</th>
<th>Status</th>
<th>Type</th>
</tr>
</tfoot>
<tbody>
<tr role="row" class="odd">
<td class="sorting_1">27-03-2019</td>
<td>521735</td>
<td>£5.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
<tr role="row" class="even">
<td class="sorting_1">27-03-2019</td>
<td>513938</td>
<td>£1.20</td>
<td>overdue</td>
<td>Cash</td>
</tr>
<tr role="row" class="odd">
<td class="sorting_1">27-03-2019</td>
<td>523693</td>
<td>£0.20</td>
<td>overdue</td>
<td>Cash</td>
</tr>
<tr role="row" class="even">
<td class="sorting_1">27-03-2019</td>
<td>493645</td>
<td>£0.10</td>
<td>overdue renewed</td>
<td>Cash</td>
</tr>
<tr role="row" class="odd">
<td class="sorting_1">27-03-2019</td>
<td>521734</td>
<td>£0.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
<tr role="row" class="even">
<td class="sorting_1">27-03-2019</td>
<td>493646</td>
<td>£0.10</td>
<td>overdue renewed</td>
<td>Cash</td>
</tr>
<tr role="row" class="odd">
<td class="sorting_1">27-03-2019</td>
<td>523691</td>
<td>£0.10</td>
<td>overdue renewed</td>
<td>Card</td>
</tr>
<tr role="row" class="even">
<td class="sorting_1">27-03-2019</td>
<td>523692</td>
<td>£0.10</td>
<td>overdue renewed</td>
<td>Card</td>
</tr>
<tr role="row" class="odd">
<td class="sorting_1">26-03-2019</td>
<td>523694</td>
<td>£0.20</td>
<td>overdue</td>
<td>Cash</td>
</tr>
<tr role="row" class="even">
<td class="sorting_1">26-03-2019</td>
<td>506326</td>
<td>£1.20</td>
<td>overdue</td>
<td>Card</td>
</tr>
</tbody>
</table>
Not to create a lot of smoke around very basic one-liner, I'll demonstrate my solution on distilled example, sure, you'll grasp the idea, which is pretty much straightforward - refresh totals upon each table redraw (which is triggered by filtering every time), using drawCallback:
//table source data
const srcData = [
{item: 'apple', category: 'fruit', qty: 5},
{item: 'banana', category: 'fruit', qty: 4},
{item: 'pear', category: 'fruit', qty: 8},
{item: 'carrot', category: 'vegie', qty: 4},
{item: 'cabbage', category: 'vegie', qty: 7}
];
//initialize DataTable
const dataTable = $('#mytable').DataTable({
dom: 'ft',
data: srcData,
columns: Object.keys(srcData[0]).map(key => ({title:key, data:key})),
//refresh your totals upon each table redraw, triggered by filtering
drawCallback: function(){
$('#totals').text((this.api().rows({search:'applied'}).data().toArray().reduce((total, item) => total += item.category == 'fruit' ? item.qty : 0, 0)));
}
});
<!doctype html>
<html>
<head>
<script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
</head>
<body>
Total qty of fruits: <span id="totals"></span>
<table id="mytable"></table>
</body>
</html>
I have a html table that i want to convert into json format but i'm not getting correctly.
the resultant json is not coming according to my format
here is my table
<table class="table" id="example-table">
<thead>
<tr>
<th>Product Name</th>
<th>Price</th>
<th>Quantity</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr class="allTheQuotationRow">
<td>flex board</td>
<td contenteditable="" class="priceChangeField">3</td>
<td contenteditable="" class="quantityChangeField">5</td>
<td>15</td>
</tr>
<tr class="allTheQuotationRow">
<td>sign board</td>
<td contenteditable="" class="priceChangeField">20</td>
<td contenteditable="" class="quantityChangeField">1</td>
<td>20</td>
</tr>
<tr class="allTheQuotationRow">
<td>flex board</td>
<td contenteditable="" class="priceChangeField">30</td>
<td contenteditable="" class="quantityChangeField">1</td>
<td>30</td>
</tr>
<tr class="allTheQuotationRow">
<td>sign board</td>
<td contenteditable="" class="priceChangeField">200</td>
<td contenteditable="" class="quantityChangeField">19</td>
<td>3800</td>
</tr>
<tr id="lastTotalRow">
<td>total</td>
<td></td>
<td></td>
<td>3865</td>
</tr>
</tbody>
</table>
i want my desired result to be like this:
{
"flex_board": [
{
"Price": 3,
"Quantity": 5,
"Amount": 15
},
{
"Price": 30,
"Quantity": 1,
"Amount": 30
}
],
"sign_board": [
{
"Price": 20,
"Quantity": 1,
"Amount": 20
},
{
"Price": 200,
"Quantity": 19,
"Amount": 3800
}
],
"total": [
{
"Price": null,
"Quantity": null,
"Amount": 3865
}
]
}
here is my jsfiddle:http://jsfiddle.net/eabangalore/cCzqn/1601/
Please help me thanks in advance!!!
Use querySelectorAll and Array.from to iterate the rows (Comments inline)
var allRows = Array.from( document.querySelectorAll( "tbody tr:not(:last-child)" ) ); //get all rows except last one
var map = {};
allRows.forEach( function( row ){
var cells = row.children;
var prodName = cells[0].innerText; //index by product name
map[ prodName ] = map[ prodName ] || []; //initialize inner array
map[ prodName ].push({ //push each row to the respective product name's index
Price : cells[1].innerText,
Quantity : cells[2].innerText,
Amount : cells[3].innerText
});
});
console.log( map );
Demo
var allRows = Array.from( document.querySelectorAll( "tbody tr:not(:last-child)" ) ); //get all rows except last one
var map = {};
allRows.forEach( function( row ){
var cells = row.children;
var prodName = cells[0].innerText; //index by product name
map[ prodName ] = map[ prodName ] || []; //initialize inner array
map[ prodName ].push({ //push each row to the respective product name's index
Price : cells[1].innerText,
Quantity : cells[2].innerText,
Amount : cells[3].innerText
});
});
console.log( map );
<table class="table" id="example-table">
<thead>
<tr>
<th>Product Name</th>
<th>Price</th>
<th>Quantity</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr class="allTheQuotationRow">
<td>flex board</td>
<td contenteditable="" class="priceChangeField">3</td>
<td contenteditable="" class="quantityChangeField">5</td>
<td>15</td>
</tr>
<tr class="allTheQuotationRow">
<td>sign board</td>
<td contenteditable="" class="priceChangeField">20</td>
<td contenteditable="" class="quantityChangeField">1</td>
<td>20</td>
</tr>
<tr class="allTheQuotationRow">
<td>flex board</td>
<td contenteditable="" class="priceChangeField">30</td>
<td contenteditable="" class="quantityChangeField">1</td>
<td>30</td>
</tr>
<tr class="allTheQuotationRow">
<td>sign board</td>
<td contenteditable="" class="priceChangeField">200</td>
<td contenteditable="" class="quantityChangeField">19</td>
<td>3800</td>
</tr>
<tr id="lastTotalRow">
<td>total</td>
<td></td>
<td></td>
<td>3865</td>
</tr>
</tbody>
</table>
Refactoring an array like that can be a complicated procedure, but thankfully there is a library called lodash that has a function called groupBy. It can fix your problem in a single line of code!
_.groupBy(table, "Product Name")
That's really it!
Lodash Library
http://jsfiddle.net/nhc6m1af/
You can use reduce to convert your Array into desired Object
$('#convert-table').click(function() {
var table = $('#example-table').tableToJSON();
var result = table.reduce(function(acc, item) {
var key = item["Product Name"].replace(/ /g, "_");
if (!acc[key]) {
acc[key] = []
}
acc[key].push({
Price: item.Price,
Quantity: item.Quantity,
Amount: item.Amount
})
return acc;
}, {});
console.log(result);
});
jsFiddle Link : http://jsfiddle.net/scorpy2007/cCzqn/1603/
You can use same tableToJSON data object in generating your customized format as shown below
var jsondata={};
table.forEach( function( data ){
var prodName = data["Product Name"];
jsondata[ prodName ] = jsondata[ prodName ] ?jsondata[ prodName ]: [];
jsondata[ prodName ].push({
Price : data['Price'],
Quantity : data['Quantity'],
Amount : data['Amount']
});
});
console.log(JSON.stringify(jsondata));
Working fiddle here
I have a table that uses DataTables. The table consists of 4 columns and has text in some and numbers in some as well. Within the numbers column if there is no number then 'null' is shown in the td. How can I still sort the numbers correctly and give the null value a 0 or some number to help sort better?
Right now when you sort through the list it's not sorting more than one digit. So '10' comes before '3'. Also, do you notice the 1440 comes before 180.
You can view my http://codepen.io/tetonhiker/pen/dOBeqY
$(function() {
$('#dataTable').DataTable({
"paging": false,
"info": false
});
});
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
<link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.13/css/jquery.dataTables.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<script src="https://cdn.datatables.net/1.10.13/js/jquery.dataTables.js"></script>
<table id="dataTable" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp dataTable">
<thead>
<tr role="row">
<th class="mdl-data-table__cell--non-numeric">Shape Name</th>
<th class="numeric-cell">Number Edges</th>
<th class="numeric-cell">Sum of Interior Angles</th>
<th class="mdl-data-table__cell--non-numeric">Deleted?</th>
</tr>
</thead>
<tbody>
<tr class="rowEditData odd" value="7924" role="row" title="">
<td class="mdl-data-table__cell--non-numeric">Hexagon</td>
<td class="numeric-cell">6</td>
<td class="numeric-cell">null</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData odd deleted" value="7930" role="row" title="">
<td class="mdl-data-table__cell--non-numeric">null</td>
<td class="numeric-cell">3</td>
<td class="numeric-cell">180</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData even" value="7931" role="row">
<td class="mdl-data-table__cell--non-numeric">null</td>
<td class="numeric-cell">4</td>
<td class="numeric-cell">360</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData odd" value="7932" role="row" title="">
<td class="mdl-data-table__cell--non-numeric">null</td>
<td class="numeric-cell">5</td>
<td class="numeric-cell">540</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData even" value="7933" role="row">
<td class="mdl-data-table__cell--non-numeric">null</td>
<td class="numeric-cell">6</td>
<td class="numeric-cell">120</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData odd" value="7934" role="row">
<td class="mdl-data-table__cell--non-numeric">null hello</td>
<td class="numeric-cell">10</td>
<td class="numeric-cell">1440</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData even" value="7925" role="row">
<td class="mdl-data-table__cell--non-numeric">Octagon sample</td>
<td class="numeric-cell">8</td>
<td class="numeric-cell">null</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData odd" value="7922" role="row">
<td class="mdl-data-table__cell--non-numeric">pentagon</td>
<td class="numeric-cell">null</td>
<td class="numeric-cell">null</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData even deleted" value="7926" role="row">
<td class="mdl-data-table__cell--non-numeric">Pentagon</td>
<td class="numeric-cell">null</td>
<td class="numeric-cell">null</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData odd" value="7920" role="row">
<td class="mdl-data-table__cell--non-numeric">square-test</td>
<td class="numeric-cell">4</td>
<td class="numeric-cell">null</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
<tr class="rowEditData even" value="7927" role="row">
<td class="mdl-data-table__cell--non-numeric">Square</td>
<td class="numeric-cell">null</td>
<td class="numeric-cell">null</td>
<td class="mdl-data-table__cell--non-numeric">No</td>
</tr>
</tbody>
</table>
Try out this sorting plugin for DataTables: https://datatables.net/plug-ins/sorting/natural
(function() {
/*
* Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
* Author: Jim Palmer (based on chunking idea from Dave Koelle)
* Contributors: Mike Grier (mgrier.com), Clint Priest, Kyle Adams, guillermo
* See: http://js-naturalsort.googlecode.com/svn/trunk/naturalSort.js
*/
function naturalSort (a, b, html) {
var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?%?$|^0x[0-9a-f]+$|[0-9]+)/gi,
sre = /(^[ ]*|[ ]*$)/g,
dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
hre = /^0x[0-9a-f]+$/i,
ore = /^0/,
htmre = /(<([^>]+)>)/ig,
// convert all to strings and trim()
x = a.toString().replace(sre, '') || '',
y = b.toString().replace(sre, '') || '';
// remove html from strings if desired
if (!html) {
x = x.replace(htmre, '');
y = y.replace(htmre, '');
}
// chunk/tokenize
var xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
// numeric, hex or date detection
xD = parseInt(x.match(hre), 10) || (xN.length !== 1 && x.match(dre) && Date.parse(x)),
yD = parseInt(y.match(hre), 10) || xD && y.match(dre) && Date.parse(y) || null;
// first try and sort Hex codes or Dates
if (yD) {
if ( xD < yD ) {
return -1;
}
else if ( xD > yD ) {
return 1;
}
}
// natural sorting through split numeric strings and default strings
for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
var oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc], 10) || xN[cLoc] || 0;
var oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc], 10) || yN[cLoc] || 0;
// handle numeric vs string comparison - number < string - (Kyle Adams)
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
return (isNaN(oFxNcL)) ? 1 : -1;
}
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
else if (typeof oFxNcL !== typeof oFyNcL) {
oFxNcL += '';
oFyNcL += '';
}
if (oFxNcL < oFyNcL) {
return -1;
}
if (oFxNcL > oFyNcL) {
return 1;
}
}
return 0;
}
jQuery.extend( jQuery.fn.dataTableExt.oSort, {
"natural-asc": function ( a, b ) {
return naturalSort(a,b,true);
},
"natural-desc": function ( a, b ) {
return naturalSort(a,b,true) * -1;
},
"natural-nohtml-asc": function( a, b ) {
return naturalSort(a,b,false);
},
"natural-nohtml-desc": function( a, b ) {
return naturalSort(a,b,false) * -1;
},
"natural-ci-asc": function( a, b ) {
a = a.toString().toLowerCase();
b = b.toString().toLowerCase();
return naturalSort(a,b,true);
},
"natural-ci-desc": function( a, b ) {
a = a.toString().toLowerCase();
b = b.toString().toLowerCase();
return naturalSort(a,b,true) * -1;
}
} );
}());
You have the class "non-numeric" in each row, which tells this weird plugin not to sort those columns as numbers. Remove that string.
This code works but checks only the first column. I want to check the 2nd column instead with the points. How do I alter it?
HTML Table:
<table width="100%">
<thead>
<tr>
<th width="60%">Name</th>
<th width="20%">School</th>
<th width="20%">Points</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="4"><h1>Event 1</h1></td>
<td>School1</td>
<td>74</td>
</tr>
<tr>
<td>School2</td>
<td>69</td>
</tr>
<tr>
<td>School3</td>
<td>71</td>
</tr>
<tr>
<td>School4</td>
<td>11</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="4"><h1>Event 2</h1></td>
<td>School1</td>
<td>34</td>
</tr>
<tr>
<td>School5</td>
<td>29</td>
</tr>
<tr>
<td>School3</td>
<td>62</td>
</tr>
<tr>
<td>School7</td>
<td>15</td>
</tr>
</tbody>
</table>
jQuery:
var $tbody = $('#caltbl tbody');
$tbody.find('tr').sort(function (a, b) {
var tda = $(a).find('td:eq(0)').text();
var tdb = $(b).find('td:eq(0)').text();
// if a < b return 1
return tda > tdb ? 1
// else if a > b return -1
: tda < tdb ? -1
// else they are equal - return 0
: 0;
}).appendTo($tbody);
How do I got about this?
JSFIDDLE
EDIT: I'm sorry guys but my live code is different with rowspan being used. Is there a possibility to have this in ascending order so that the events are sorted differently?
eq(0) means you are using the first index. Change it to eq(1) so that it can consider the second index.
var tda = $(a).find('td:eq(1)').text();
var tdb = $(b).find('td:eq(1)').text();
You can sort the trs. Detach the td and insert to an array. Then append them back to each row
Add some class to simplify coding.
JSFIDDLE
HTML
<table width="100%">
<thead>
<tr>
<th width="60%">Name</th>
<th width="20%">School</th>
<th width="20%">Points</th>
</tr>
</thead>
<tbody>
<tr class="event1">
<td rowspan="4"><h1>Event 1</h1></td>
<td>School1</td>
<td class="point">74</td>
</tr>
<tr class="event1">
<td>School2</td>
<td class="point">69</td>
</tr>
<tr class="event1">
<td>School3</td>
<td class="point">71</td>
</tr>
<tr class="event1">
<td>School4</td>
<td class="point">11</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="4"><h1>Event 2</h1></td>
<td>School1</td>
<td>34</td>
</tr>
<tr>
<td>School5</td>
<td>29</td>
</tr>
<tr>
<td>School3</td>
<td>62</td>
</tr>
<tr>
<td>School7</td>
<td>15</td>
</tr>
</tbody>
</table>
JavaScript
var $tbody = $(' tbody');
var array = [];
$tbody.find('.event1').sort(function (a, b) {
var tda = $(a).find('.point').text();
var tdb = $(b).find('.point').text();
return tda - tdb;
}).each(function (idx, tr) {
array.push($(tr).children('td').not('[rowspan]').detach());
});
$.each(array, function (idx, obj) {
$(obj).appendTo($('.event1:eq(' + idx + ')'));
});
The JavaScript only applies to event1. You can simply modify it for arbitrary events.
Change the index as Mayank Pandey said. And..
Since your second column is number, you can just return their difference.
var $tbody = $('#caltbl tbody');
$tbody.find('tr').sort(function (a, b) {
var tda = parseInt($(a).find('td:eq(1)').text(), 10); // always use the base number
var tdb = parseInt($(b).find('td:eq(1)').text(), 10);
return tda - tdb;
}).appendTo($tbody);