There is no problem updating the current page(websocket).
However, other pages are not updated, so filter is not working properly.
further explanation
There's about 2,000 data, updated in real time.
If all 2000 data are displayed on one page without pagiation, all data is updated without any problems, and the ordering filter is also refreshed every 10 seconds with no problem.
The problem is that when pagination is performed, for example, when displaying 100 data per page,
Only 100 data is updated and the rest of the data is not updated. As a result, the ordering filter is not working properly.
-- js code It is refreshed every 10 seconds(setInterval)Customized for numerical sorting.(dom-text-numeric)
/* Create an array with the values of all the input boxes in a column, parsed as numbers */
$.fn.dataTable.ext.order['dom-text-numeric'] = function (settings, col) {
return this.api()
.column(col, {order: 'index'})
.nodes()
.map(function (td, i) {
return $(td).text() * 1;
});
};
/* Initialise the table with the required column ordering data types */
$(document).ready(function () {
var myTable = $('#example').DataTable({
responsive: true,
//paging: false,
pageLength:100,
columns: [
null,
{orderDataType: 'dom-text-numeric'},
{orderDataType: 'dom-text-numeric'},
{orderDataType: 'dom-text-numeric'},
],
order: [[1, 'desc']],
});
setInterval(function () {
myTable.rows().invalidate().draw();
}, 10000);
});
html--This is some rendered data.
<table id="example" class="table table-striped table-bordered dt-responsive nowrap w-100 dataTable no-footer" style="width: 100%;" aria-describedby="example_info">
<thead>
<tr>
<th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="Name: activate to sort column ascending" style="width: 442px;">Name</th>
<th class="sorting sorting_desc" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="premium: activate to sort column ascending" style="width: 282px;" aria-sort="descending">premium</th>
<th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="binance: activate to sort column ascending" style="width: 292px;">binance</th>
<th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" aria-label="upbit: activate to sort column ascending" style="width: 346px;">upbit</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="name_DNT-BTC">DNT-BTC</td>
<td class="premium_DNT-BTC sorting_1">1.0087</td>
<td class="binanceSpot_DNTBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000233</td>
<td class="upbitSpot_BTC-DNT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000231</td>
</tr>
<tr class="even">
<td class="name_SNT-BTC">SNT-BTC</td>
<td class="premium_SNT-BTC sorting_1">1.0072</td>
<td class="binanceSpot_SNTBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000138</td>
<td class="upbitSpot_BTC-SNT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
</tr>
<tr class="odd">
<td class="name_TRX-BTC">TRX-BTC</td>
<td class="premium_TRX-BTC sorting_1">1.0067</td>
<td class="binanceSpot_TRXBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00000299</td>
<td class="upbitSpot_BTC-TRX" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
</tr>
<tr class="even">
<td class="name_ETH-USDT">ETH-USDT</td>
<td class="premium_ETH-USDT sorting_1">1.0053</td>
<td class="binanceSpot_ETHUSDT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">1681.08</td>
<td class="upbitSpot_USDT-ETH" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">1672.2989054</td>
</tr>
<tr class="odd">
<td class="name_ETH-BTC">ETH-BTC</td>
<td class="premium_ETH-BTC sorting_1">1.0050</td>
<td class="binanceSpot_ETHBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.073392</td>
<td class="upbitSpot_BTC-ETH" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
</tr>
<tr class="even">
<td class="name_LINK-BTC">LINK-BTC</td>
<td class="premium_LINK-BTC sorting_1">1.0047</td>
<td class="binanceSpot_LINKBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.0003658</td>
<td class="upbitSpot_BTC-LINK" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00036409</td>
</tr>
<tr class="odd">
<td class="name_LRC-BTC">LRC-BTC</td>
<td class="premium_LRC-BTC sorting_1">1.0047</td>
<td class="binanceSpot_LRCBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00001917</td>
<td class="upbitSpot_BTC-LRC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">-</td>
</tr>
<tr class="even">
<td class="name_BNT-BTC">BNT-BTC</td>
<td class="premium_BNT-BTC sorting_1">1.0040</td>
<td class="binanceSpot_BNTBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00002527</td>
<td class="upbitSpot_BTC-BNT" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00002537</td>
</tr>
<tr class="odd">
<td class="name_EOS-BTC">EOS-BTC</td>
<td class="premium_EOS-BTC sorting_1">1.0025</td>
<td class="binanceSpot_EOSBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.0000513</td>
<td class="upbitSpot_BTC-EOS" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00005143</td>
</tr>
<tr class="even">
<td class="name_XRP-BTC">XRP-BTC</td>
<td class="premium_XRP-BTC sorting_1">1.0025</td>
<td class="binanceSpot_XRPBTC" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00001574</td>
<td class="upbitSpot_BTC-XRP" data-bs-toggle="modal" data-bs-target="#bookModal" onclick="setOrderbookPair(this.className)">0.00001578</td>
</tr>
</tbody>
</table>
--js -socket Receives real-time data from the Beckend Consumer (via on-message.)
function auto_reconnect_ticker_socket() {
let ws = new WebSocket(
'ws://' + window.location.host +
'/ws/ticker?session_key=${sessionKey}')
ws.onopen = function () {
// subscribe to some channels
ws.send(JSON.stringify({
//.... some message the I must send when I connect ....
}));
};
ws.onmessage = function (e) {
let data = JSON.parse(e.data);
let site = data['site'];
let type = data['type'];
if (type == 'ticker') {
data['data'].forEach((c, i, a) => {
document.querySelector(`.${site}_${c.symbol}`) && update_price(site, c.symbol, c.price_trade)
document.querySelector(`.${site}_${c.symbol}`) && update_premium(c.name, c.premium)
//&& update_price_change_24h(site, c.s, c.o, c.c)
});
}
}
ws.onclose = function (e) {
console.log('Ticker Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function () {
auto_reconnect_ticker_socket();
}, 1000);
};
ws.onerror = function (err) {
auto_reconnect_ticker_socket.error('Socket encountered error: ', err.message, 'Closing socket');
ws.close();
};
return ws
}
Is there a way to update other pages with the DataTables?
Your code is currently updating data in the DOM using query selectors such as:
document.querySelector(`.${site}_${c.symbol}`) && update_price(site, c.symbol, c.price_trade)
This will only update the HTML for data on the currently visible page (as you have noted). DataTables will not know anything about these changes.
Instead you need to use the DataTables API when performing your data updates.
One way to do this is to use a column containing a unique identifier - which in your case appears to be column 1 (index 0) - the "Name" column.
To update existing records in the table, I would use the following approach.
This assumes you get one name per socket event e. If you get an array of names, then you would adjust to loop through each one, and only perform one draw() at the end:
function updateTable(e) {
let pairData = JSON.parse(e.data);
// check if "name" already exists in table:
var index = table.column( 0, {order:'index'} ).data()
.indexOf( pairData.name);
if (index >= 0) {
// update the existing row:
table.row( index, {order:'index'} ).data( pairData ).draw();
} else {
// insert a new row:
table.row.add( pairData ).draw();
}
}
You will need to adjust the above for your specific JSON contents. I use data for the contents of a row, and name for the unique identifier in each row.
indexOf() - searches in column zero and locates the row index containing the unique name (e.g. DNT-BTC). It uses {order:'index'} to ensure the value returned represents the internally assigned index number used by DataTables (based on the initial data load order), not an index number dependent on filtering and/or sorting.
row().data( newdata ) - retrieves the row of data for the previously found index number. Updates the data for that row. Re-draws the table.
Note that newdata can be an array or an object - depending on how the original row of data was created in DataTables. In my code, I assume an object (the JSON message). In your question, you show the original data as being provided directly from the initial HTML - so that would be an array of data, not an object:
[ 'DNT-BTC', 1.0087, 0.00000233, 0.00000231 ]
Finally, my code also inserts a new record, if its key value was not found anywhere in the DataTable. You may not need that, in your case.
The benefit of this approach is that it operates on the underlying DataTable via its API, and not on the DOM, which may only display part of that underlying data. Also, if you only change values in the DOM, then any draw() call will cause that data to be lost (because such DOM changes do not exist in the underlying DataTables data).
Related
I have my code for a table that I created in html with one row, but I want to add more rows to it, the number of total rows has to be equal to the value that my combox takes (24,36,48 rows in total):
<div id="visible" class="table-responsive">
<table class="table " id="tablacondatos" name="tablacondatos">
<thead>
<tr>
<th scope="col">MES</th>
<th scope="col">CUOTA</th>
<th scope="col">INTERES</th>
<th scope="col">AMORTI.</th>
<th scope="col">CAPITAL</th>
<th scope="col">SEGURO DESGRAV.</th>
<th scope="col">SEGURO INMOBIL.</th>
<th scope="col">GASTOS ADM.</th>
<th scope="col">CUOTA FINAL</th>
</tr>
</thead>
<tbody id="cuerpotabla" name="cuerpotabla">
<tr id="filamaestra">
<td id="mes" name="mes">0</td>
<td id="cuota" name="cuota">0</td>
<td id="interes" name="interes">0</td>
<td id="amorti" name="amorti">0</td>
<td id="capital" name="capital">0</td>
<td id="segurodesgrav" name="segurodesgrav">0</td>
<td id="seguroinmobil" name="seguroinmobil">0</td>
<td id="gastosadm" name="gastosadm">0</td>
<td id="cuotafinal" name="cuotafinal">0</td>
</tr>
</tbody>
</table>
</div>
This is how I get the value of my combo for the rows:
ahorrar = document.getElementById("plazooperacion").value; // 24,36,48 rows
I am using this code to add rows, but the problem is that it generates too many rows, and in the first cells I am putting a counter, which goes from 1 to 24, or 1 to 36 or from 1 to 48; but it generates them backwards (it puts the last one first and the first one last):
ms=ms+1; //accountant
var table = document.getElementById("cuerpotabla");
var row = table.insertRow(0);
//this adds row in 0 index i.e. first place
row.innerHTML = "<td>"+ms+"</td><td id='cuota' name ='cuota'>"+cuota+"</td><td id='interes' name='interes'>"+interes+"</td><td id='amorti' name='amorti'>"+amorti+
"</td><td id='capital' namre='capital'>"+capital+"</td><td id='segurodesgrav' name='segurodesgrav'>"+segurodesgrav+"</td><td id='seguroinmobil' name='seguroinmobil'>"+seguroinmobil+"</td><td id='gastosadm' namre='gastosadm'>"+gastosadm+"</td><td id='cuotafinal' name='cuotafinal'>"+cuotafinal+"</td>";
I am implementing the IGV genome browser in a website.
I would like to link a table with chromosome positions to the genome browser, so when a user clicks to one position, the genome browser changes to that position automatically.
By now, I have the genome browser code in a separate javascript file, which uses the value of the button.
// Construct genome browser
document.addEventListener("DOMContentLoaded", function () {
// Obtain position
var position = $('#ins').val();
// Use the position
var options = {locus: position, ...};
var igvDiv = document.getElementById("igvDiv");
igv.createBrowser(igvDiv, options)
.then(function (browser) {
console.log("Created IGV browser");
})
};
And the table in html with buttons.
<table class='results-table'>
<tr>
<th class='text text--bold'>Chromosome</th>
<th class='text text--bold'>Start</th>
<th class='text text--bold'>End</th>
<th class='text text--bold'>Genome Browser</th>
</tr>
<tr>
<td class='text'>chr1</td>
<td class='text'>0</td>
<td class='text'>100</td>
<td><button class='editbtn' value='chr1:0-100' id='ins1'>chr1:0-100</button></td>
</tr>
<tr>
<td class='text'>chr2</td>
<td class='text'>200</td>
<td class='text'>400</td>
<td><button class='editbtn' value='chr2:200-400' id='ins2'>chr2:200-400</button></td>
</tr>
</table>
With this, the browser gets the first position but it does not change when I click the button.
I think I need some kind of onClick() action but I can't figure out how to change a javascript script.
Any help would be appreciated.
Thank you!
JĂșlia
edit:
I added more javascript code as I think that I was not able to illustrate my question properly. And also modified the ids from buttons, to make them different.
The question is how to use different ids in javascript depending on the button that was clicked.
You can change some things. I remove the id from your buttons because you will already have the context with the passing event. And instead of a value in the button, I would recommend you to use a data attribute. data-value for example.
function check(e) {
console.log(e.getAttribute('data-value'))
}
<button class='editbtn' onclick="check(this)" data-value='chr2:200-400' >chr2:200-400</button>
<button class='editbtn' onclick="check(this)" data-value='chr1:0-100' >chr1:0-100</button>
You can access the ID and value in a click event:
// Construct genome browser
document.querySelector('table.results-table').addEventListener('click', function ({ target }) {
if (!target.id) return;
const id = target.id;
const position = target.value;
console.log(id);
console.log(position);
});
<table class='results-table'>
<tr>
<th class='text text--bold'>Chromosome</th>
<th class='text text--bold'>Start</th>
<th class='text text--bold'>End</th>
<th class='text text--bold'>Genome Browser</th>
</tr>
<tr>
<td class='text'>chr1</td>
<td class='text'>0</td>
<td class='text'>100</td>
<td><button class='editbtn' value='chr1:0-100' id='ins1'>chr1:0-100</button></td>
</tr>
<tr>
<td class='text'>chr2</td>
<td class='text'>200</td>
<td class='text'>400</td>
<td><button class='editbtn' value='chr2:200-400' id='ins2'>chr2:200-400</button></td>
</tr>
</table>
I have a table with following rows and cells:
<table id='table1'>
<tr id='row1'>
<th>index</th>
<th>Product</th>
<th>Description</th>
</tr>
<tr id='row2' name='row'>
<td name='index'>1</td>
<td name='product'>Apples</td>
<td name='description'>fruits</td>
</tr>
<tr id='row3' name='row'>
<td name='index'>2</td>
<td name='product'>Bananas</td>
<td name='description'>fruits</td>
</tr>
<tr id='row4' name='row'>
<td name='index'>3</td>
<td name='product'>Carrots</td>
<td name='description'>vegetables</td>
</tr>
<tr id='row5' name='row'>
<td name='index'></td>
<td name='product'></td>
<td name='description'></td>
</tr>
</table>
I need to select the value for the last td with name='index' which is not null. Anyone has any idea how can this be done.
Use the following selector :
$('td[name=index]:not(:empty):last')
For purely educational purposes, here is a non jQuery version:
function getLastNonEmptyCell(tableSelector) {
//Find parent table by selector
var table = document.querySelector(tableSelector)
//Return null if we can't find the table
if(!table){
return null;
}
var cells = table.querySelectorAll("td")
var lastNonEmptyCell = null;
//Iterate each cell in the table
//We can just overwrite lastNonEmptyCell since it's a synchronous operation and the return value will be the lowest item in the DOM
cells.forEach(function(cell) {
//!! is used so it's so if it is not null, undefined, "", 0, false
//This could be changed so it's just cell.innerText.trim() !== ""
if (!!cell.innerText) {
lastNonEmptyCell = cell;
}
})
return lastNonEmptyCell;
}
var cell = getLastNonEmptyCell("#table1")
Edit
As #squint suggested this can be done much more succintly:
function lastNonEmptyCell(tableSelector) {
//Since we want the last cell that has content, we get the last-child where it's not empty. This returns the last row.
var row = document.querySelectorAll(tableSelector + " td:not(:empty):last-child")
//Just grabbing the last cell using the index
return row[row.length - 1]
}
i am passing a very hard time with my web project.because i am new with web related languages.
i just want to get data of a cell by clicking the same row button of the other cell. i am adding a pic please see this first.
i try with many codes like below---(1st try)
my js code-
var tbl = document.getElementById("myTable");
if (tbl != null) {
for (var i = 0; i < tbl.rows.length; i++) {
tbl.rows[i].cells[1].onclick = function (){ getval(this); };
}
}
function getval(cell) {
value(cell.innerHTML);
}
my html code
<table class="w3-table-all w3-margin-top" id="myTable">
<tr>
<th style="width:25%;">Vendor Picture Path</th>
<th style="width:25%;">Vendor Heading</th>
<th style="width:25%;">Vendor Body</th>
<th style="width:25%;">Add courses</th>
</tr>
echo '<tr>
<td>'.$row["pic_path"].'</td>
<td style="cursor: pointer;color:red;">'.$row["heading"].'</td>
<td><div style="width:100%;height: 60px;margin: 0;padding: 0;overflow-y: scroll">'.$row["body"].'</div></td>
<td><button>Add</button></td>
</tr>';
my table data contains echo because i fatch the table data from my sql server.
my second try...
js code
var tb2=document.getElementById("myTable");
if(tb2 != null)
{
for(h=0;h<tb2.rows.length;h++)
{
bf=tb2.rows[h].cells[1];
tb2.rows[h].cells[3].onclick=function(){getbtval(bf);};
}
}
function getbtval(cell)
{
alert(cell.innerHTML);
}
and html code same...
1st one work for me.but that was not my expected result.
my code success on second one result.but that fails.when i click every add button it gives me just the last value of 2nd cell last row and that is "ORACLE".
PLEASE TELL ME WHAT IS WRONG WITH MY CODE......
Problem with your code is the fact you are not binding events to the button, you are picking a random cell of the table row. And the other issue is the fact you are not using var so it makes things global.
You said you want to click the button, but your code is not selecting the button. So instead of adding events all over the place, just use one and let event delegation take care of it. Check to see what triggered the event. If it is a button, than select the row and than you can read the text of the cells.
document.getElementById("myTable").addEventListener("click", function(evt) {
var btn = evt.target;
if(btn.tagName==="BUTTON"){
var row = btn.parentNode.parentNode; //td than tr
var cells = row.getElementsByTagName("td"); //cells
console.log(cells[0].textContent, cells[1].textContent);
}
});
<table class="w3-table-all w3-margin-top" id="myTable">
<tr>
<th style="width:25%;">Vendor Picture Path</th>
<th style="width:25%;">Vendor Heading</th>
<th style="width:25%;">Vendor Body</th>
<th style="width:25%;">Add courses</th>
</tr>
<tr>
<td>123</td>
<td style="cursor: pointer;color:red;">YYYY</td>
<td>
<div style="width:100%;height: 60px;margin: 0;padding: 0;overflow-y: scroll">XXX</div>
</td>
<td>
<button>Add</button>
</td>
</tr>
<tr>
<td>456</td>
<td style="cursor: pointer;color:red;">dasdas</td>
<td>
<div style="width:100%;height: 60px;margin: 0;padding: 0;overflow-y: scroll">qwwqeqwe</div>
</td>
<td>
<button>Add</button>
</td>
</tr>
</table>
cell.onclick = function (){ getval(this); };
this means "current context", that is the cell which produced the click event.
bf=tb2.rows[h].cells[1];
tb2.rows[h].cells[3].onclick=function(){getbtval(bf);};
After the for loop, bf points to the cell in the last row, so getval(bf) returns the value of it.
To access the proper cell, do the DOM traversal as #epascarello suggests. Depending on your use-case, it also might be easier to use data attribute:
<button data-value="Cisco">
And then in the JS code
button.onclick = function() { alert(this.dataset.value); }
You need to first identify the row clicked, for this you can check which element is current clicked by adding an event listener on the entire table and check when the target is button.
Once you get the event target as button , find its parent td and its parent tr.
Now you got the tr and just loop through the child nodes, exclude the nodeType == 3 so that you only get the td element in the tr
document.getElementById("myTable").addEventListener("click",function(e){
e = e || event
var target = e.target || e.srcElement;
if (target.nodeName != 'BUTTON') return
var row = target.parentNode.parentNode;
row.childNodes.forEach(function(item){
if(item.nodeType !== 3)
{
console.log(item.textContent);
console.log(item.innerHTML);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="w3-table-all w3-margin-top" id="myTable">
<tr>
<th style="width:25%;">Vendor Picture Path</th>
<th style="width:25%;">Vendor Heading</th>
<th style="width:25%;">Vendor Body</th>
<th style="width:25%;">Add courses</th>
</tr>
<tr>
<td>cisco-networking.jpg</td>
<td style="cursor: pointer;color:red;">CISCO</td>
<td><div style="width:100%;height: 60px;margin: 0;padding: 0;overflow-y: scroll">CISCO systems</div></td>
<td><button>Add</button></td>
</tr>
</table>
I've done this by assigning the td an id and grabbing the text using jquery
I'm trying to write a custom parser for TableSorter that will allow me to sort letter grades dynamically across several headers in an HTML5 table. I googled like crazy and couldn't find an example of this being done already.
I am new to this, but think this could be very helpful for doing classroom sorting, QA reporting, etc. Here I am sorting Free2Work rankings of brands into something I can use on my smartphone.
There are at least two problems here:
I got one working in Firefox, but when I load it in Chrome the sort appears random. I'm sure I'm loading the wrong things into the array somewhere, but I'm not sure what it is.
The "rating" column sorts properly in Firefox, but it looks like the other columns are not. Same parser for all columns.
Here's the JavaScript I'm using:
$.tablesorter.addParser({
id: 'grades',
is: function(s) {
return false;
},
format: function(s) {
// format your data for normalization
return s.toLowerCase()
.replace("a+",12)
.replace("a",11)
.replace("a-",10)
.replace("b+",09)
.replace("b",08)
.replace("b-",07)
.replace("c+",06)
.replace("c",05)
.replace("c-",04)
.replace("d+",03)
.replace("d",02)
.replace("d-",01)
.replace("f",00);
},
type: 'numeric'
});
$(function() {
$('#brands').tablesorter({
headers: {
2: {sorter:'grades'},
3: {sorter:'grades'},
4: {sorter:'grades'},
5: {sorter:'grades'},
6: {sorter:'grades'}
}
});
});
And here's the [truncated] html.
<table id="brands" class="tablesorter table striped">
<caption>
Brand Ratings
</caption>
<thead>
<tr>
<th>Logo</th>
<th>Brand</th>
<th class="extractor-select sorter-grades">Rating</th>
<th class="extractor-select sorter-grades">Policy</th>
<th class="extractor-select sorter-grades">Honesty</th>
<th class="extractor-select sorter-grades">Monitor</th>
<th class="extractor-select sorter-grades">Workers</th>
<th>More</th>
</tr>
</thead>
<tbody>
<tr>
<td class="brand-logo"></td>
<td class="brand-name">Etiko</td>
<td class="brand-overall-grade aplus">A+</td>
<td class="aplus">A+</td>
<td class="aplus">A+</td>
<td class="a">A</td>
<td class="aplus">A+</td>
<td class="score-card-button">
Scorecard
</td>
</tr>
<tr>
<td class="brand-logo"></td>
<td class="brand-name">Pants to Poverty</td>
<td class="brand-overall-grade aplus">A+</td>
<td class="aplus">A+</td>
<td class="aplus">A+</td>
<td class="a">A</td>
<td class="aplus">A+</td>
<td class="score-card-button">
Scorecard
</td>
</tr>
<tr>
<td class="brand-logo"><img src="http://widgets.free2work.org/images/Brand/playtex_logo_black0.jpg"></td>
<td class="brand-name">Playtex</td>
<td class="brand-overall-grade a">A</td>
<td class="aminus">A-</td>
<td class="a">A</td>
<td class="a">A</td>
<td class="aminus">A-</td>
<td class="score-card-button">
Scorecard
</td>
</tr>
<tr>
<td class="brand-logo"><img src="http://widgets.free2work.org/images/Brand/Hanes_Logo0.jpg"></td>
<td class="brand-name">Hanes</td>
<td class="brand-overall-grade a">A</td>
<td class="aminus">A-</td>
<td class="a">A</td>
<td class="a">A</td>
<td class="aminus">A-</td>
<td class="score-card-button">
Scorecard
</td>
</tr>
<tr>
<td class="brand-logo"></td>
<td class="brand-name">Voodoo Hosiery</td>
<td class="brand-overall-grade b">B</td>
<td class="aminus">A-</td>
<td class="bminus">B-</td>
<td class="b">B</td>
<td class="d">D</td>
<td class="score-card-button">
Scorecard
</td>
</tr>
<tr>
<td class="brand-logo"><img src="http://widgets.free2work.org/images/Brand/AmericanBodyArmor0.jpg"></td>
<td class="brand-name">American Body Armor</td>
<td class="brand-overall-grade f">F</td>
<td class="f">F</td>
<td class="f">F</td>
<td class="f">F</td>
<td class="f">F</td>
<td class="score-card-button">
Scorecard
</td>
</tr>
</tbody>
</table>
Anyone have any insight into how I've misconstructed something here? I'm in a bit over my head.
It appears that the demo is using two versions of tablesorter, the original tablesorter (v2.0.5) included in the javascript frame (at the bottom) and my fork of tablesorter loaded from a CDN. They both use the same parser code, so that isn't an issue.
But, there are two issues with the custom parser code (fixed demo):
When the replace is done, it is being replaced by a digit (numeric value), but it's really still a string. So I wrapped the values in quotes otherwise the leading zero will be removed. This isn't a problem with the fork of tablesorter since it uses a natural sort, but the original uses a standard sort which doesn't sort numbers inside of strings as you would expect.
Because we're actually dealing with strings, the parser type needs to be changed to "text"
Here is an updated parser cdoe:
$.tablesorter.addParser({
id: 'grades',
is: function(s) {
return false;
},
format: function(s) {
// format your data for normalization
return s.toLowerCase()
.replace("a+", '12')
.replace("a", '11')
.replace("a-", '10')
.replace("b+", '09')
.replace("b", '08')
.replace("b-", '07')
.replace("c+", '06')
.replace("c", '05')
.replace("c-", '04')
.replace("d+", '03')
.replace("d", '02')
.replace("d-", '01')
.replace("f", '00');
},
type: 'text'
});
Another method, which doesn't require set numeric values, adds the values to an array and then uses indexOf (or jQuery $.inArray if you need to support old IE) to get the position. That parser would be of a "numeric" type (demo)
// put grades outside of the format function, so the split
// only needs to happen once
var grades = 'a+ a a- b+ b b- c+ c c- d+ d d- f'.split(' ');
$.tablesorter.addParser({
id: 'grades',
is: function(s) {
return false;
},
format: function(s) {
var val = $.inArray( ( s || '' ).toLowerCase(), grades );
// return string if it isn't a grade (to allow sorting)
return val > -1 ? val : s;
},
type: 'numeric'
});
One last note on the differences between the original and fork is how to set the parser
The original only allows setting the column parser within the headers option.
$(function() {
$('#brands').tablesorter({
headers: {
2: {sorter:'grades'},
3: {sorter:'grades'},
4: {sorter:'grades'},
5: {sorter:'grades'},
6: {sorter:'grades'}
}
});
});
The fork still works with setting the sorter in the headers option, but the sorter can also be set using class names on the header
<th class="extractor-select sorter-grades">Rating</th>
* Note: The "extractor-select" in the class name won't work unless every cell contains a <select> element AND the parser-input-select.js file is loaded.