Datatables Update Totals Dynamically - javascript

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>

Related

Datatables Datepicker Dynamic Calculations

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.

how to convert html table into json desired format

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

How to sort numbers and text in the same column Javascript

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.

hidden column shows up when updating element

I'm using a table in which I'm displaying some objects. I'm using jquery (bad, I know. But only thing I could get working) to add/remove class ng-hide from all elements with a specific ID. This results in a column being hidden and it works fine. But when any updates from the server comes and I use $scope.rows.push(object) and $scope.apply() the order of the columns gets messed up and the hidden column gets right back..
<!doctype html>
<html ng-app="plunker">
<head>
<script data-require="angular.js#*" data-semver="1.2.0" src="http://code.angularjs.org/1.2.0/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng:controller="MainCtrl">
<table>
<thead style="font-weight: bold;">
<tr>
<td class="text-right" data-col-id="Value1">Value1</td>
<td class="text-right" data-col-id="Value2">Value2</td>
<td class="text-right" data-col-id="Value3">Value3</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows">
<td class="text-right" data-col-id="Value1">{{row.Value1}}</td>
<td class="text-right" data-col-id="Value2">{{row.Value2}}</td>
<td class="text-right" data-col-id="Value3">{{row.Value3}}</td>
</tr>
</tbody>
</table>
<p>Visible Columns:</p>
<br />
<div class="cbxList" ng-repeat="column in columnsTest">
<input type="checkbox" ng-model="column.checked" ng-change="columnToggled(column)"> {{column.id}}
</div>
</div>
<script>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.columnsTest = [{
id: 'Value1',
checked: true
}, {
id: 'Value2',
checked: true
}, {
id: 'Value3',
checked: true
}];
$scope.rows = [{
id: 1,
"Value1": 911,
"Value2": 20,
"Value3": 20
}, {
id: 2,
"Value1": 200,
"Value2": 20,
"Value3": 20
}];
$scope.columnToggled = function(column) {
$('[data-col-id="' + column.id + '"]').each(function() {
var element = this;
if ($(element).hasClass('ng-hide')) {
$(element).removeClass('ng-hide');
} else {
$(element).addClass('ng-hide');
}
});
};
//trigger update
window.setInterval(function() {
$scope.simulateUpdates($scope.rows[0]);
}, 5000);
$scope.simulateUpdates = function (row) {
var newRow =
{
id: 1,
"Value1": Math.floor(Math.random() * 100) + 1,
"Value2": Math.floor(Math.random() * 100) + 1,
"Value3": Math.floor(Math.random() * 100) + 1
}
updateRow(newRow);
$scope.$apply();
}
function updateRow(row) {
for (var i = 0; i < $scope.rows.length; i++) {
if ($scope.rows[i].id === row.id) {
$scope.rows[i] = row;
}
}
}
});
Here is a demo of my problem in a minor scale: http://plnkr.co/edit/1tGci7qX9ZFIk69uNfIf?p=preview (uncheck one of the columns)
You overcomplicate things a bit: your model seems to be pretty simple actually. The key is using templates to express it properly. That's how it might look like, for example:
<table>
<thead>
<tr>
<th class="text-right" ng-repeat="column in columnsTest"
ng-if="column.checked" ng-bind="column.id"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows">
<td ng-repeat="column in columnsTest"
ng-if="column.checked" ng-bind="row[column.id]"></td>
</tr>
</tbody>
</table>
<p>Visible Columns:</p>
<br />
<div class="cbxList" ng-repeat="column in columnsTest">
<input type="checkbox" ng-model="column.checked">{{column.id}}
</div>
See? No need for that extra function: when you change the specific column checked attribute, it's automatically updated in all the corresponding views.
Demo.
I have fixed your code without using jQuery.
<table>
<thead style="font-weight: bold;">
<tr>
<th ng-repeat="column in columnsTest" class="text-right" data-col-id="column.id" ng-show="column.checked">
{{column.id}}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows">
<td class="text-right" data-col-id="Value1" ng-show="columnsTest[0].checked">{{row.Value1}}</td>
<td class="text-right" data-col-id="Value2" ng-show="columnsTest[1].checked">{{row.Value2}}</td>
<td class="text-right" data-col-id="Value3" ng-show="columnsTest[2].checked">{{row.Value3}}</td>
</tr>
</tbody>
</table>
<div class="cbxList" ng-repeat="column in columnsTest">
<input type="checkbox" ng-model="column.checked">{{column.id}}
</div>
You don't need to bind the ng-change function to the input checkbox since you already assigned it the ng-model using two-way data-binding.
The following is the working :Plunker

table sort after new rows added

Fiddle Example
Can anyone tell me what to use to trigger initial sort after rows dynamically added to a table on page load?
$('.tablesorter2').trigger('update');
var sorting = [[1,0]];
$('.tablesorter2').trigger('sorton',sorting);
The sorton function is not working to trigger the initial sort on "Age".
Here's the full script:
var options = {
theme: 'default',
widgets: ['editable'],
widgetOptions : {
editable_columns : [0,1,2],
editable_enterToAccept : true,
editable_autoAccept : true,
editable_autoResort : false,
editable_validate : null,
editable_noEdit : 'no-edit',
editable_editComplete : 'editComplete'
}
}
$('.tablesorter2').tablesorter(options).children('tbody').on('editComplete','td', function(event, config){
var $this = $(this),
tr = $this.parent('tr'),
$allRows = config.$tbodies.children('tr'),
tid = tr.data('tid'),
input="",
name = $(this).data('name'),
newContent = $(this).text();
input = '<input value="'+newContent+'" name="'+name+'[]" type="hidden">';
$this.find('.j_input').html(input);
});
$('button').click(function(){
var item_html = "";
item_html += '<tr><td>Mary</td><td>5</td><td>Good</td><td>...</td><td><input type="checkbox"/></td></tr>';
$('tbody').append(item_html);
$('.tablesorter2').trigger('update');
var sorting = [[1,0]];
$('.tablesorter2').trigger('sorton',sorting);
});
HTML:
<button>Add</button>
<table class="tablesorter2">
<thead>
<tr data-tid='12'>
<th>Name</th>
<th>Age</th>
<th>Conditions</th>
<th>Notes</th>
<th>Del</th>
</tr>
</thead>
<tbody>
<tr data-tid='13'>
<td><div>Peter</div></td>
<td contenteditable="true" data-name='age'>18<span class='j_input'></span></td>
<td contenteditable="true" data-name='conditions'>Good<span class='j_input'></span></td>
<td contenteditable="true" data-name='notes'>...<span class='j_input'></span></td>
<td><input type='checkbox'/></td>
</tr>
<tr>
<td>Tom</td>
<td data-name='age'>12<span class='j_input'></span></td>
<td contenteditable="true" data-name='conditions'>Good<span class='j_input'></span></td>
<td contenteditable="true" data-name='notes'>On medication<span class='j_input'></span></td>
<td><input type='checkbox'/></td>
</tr>
</tbody></table>
Did you try this:
$('.tablesorter2').trigger('sorton',[sorting]);

Categories