HTML Table Multi-selection + Filter - javascript

I am having trouble getting multiselect to work properly with the filter function. If I remove multiple from $select, the function filter works properly, but adding multiple selection breaks it. Any suggestions or fix will be greatly appreciated, thank you!
The code I have below currently does not filter because of the multiple attribute, but removing it allows it to only do single selection + filtering.
<!DOCTYPE html>
<html lang="en">
<link rel="stylesheet" href="/stylesheets/style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<head>
<meta charset="utf-8">
<title>Filter</title>
</head>
</body>
</html>
<table id="myTable" class="table table-striped">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th class="dropdown-header">Age</th>
<th>Email</th>
<th class="dropdown-header">Gender</th>
<th class="dropdown-header">Term</th>
<th class="dropdown-header">Enrolled</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Smith</td>
<td data-field-name="age">15</td>
<td>123</td>
<td data-field-name="gender">Male</td>
<td data-field-name="term">Summer2017</td>
<td data-field-name="enrolled">Fall2018</td>
</tr>
<tr>
<td>Jane</td>
<td>Doe</td>
<td data-field-name="age">16</td>
<td>456</td>
<td data-field-name="gender">Female</td>
<td data-field-name="term">Fall2018</td>
<td data-field-name="enrolled">Fall2019</td>
</tr>
<tr>
<td>Bobby</td>
<td>Adams</td>
<td data-field-name="age">15</td>
<td>789</td>
<td data-field-name="gender">Male</td>
<td data-field-name="term">Spring2019</td>
<td data-field-name="enrolled">Fall2018</td>
</tr>
<tr>
<td>Sarah</td>
<td>Lee</td>
<td data-field-name="age">15</td>
<td>456</td>
<td data-field-name="gender">Female</td>
<td data-field-name="term">Fall2018</td>
<td data-field-name="enrolled">Fall2018</td>
</tr>
</tbody>
</table>
<script>
(function($) {
$.fn.tableFilterHeaders = function(filterFn) {
this.each((index, header) => {
let $header = $(header),
$table = $header.closest('table'),
text = $header.text(),
colIndex = $header.closest('th').index(),
fieldName = $header.attr('data-field-name') || text.toLowerCase(),
$select = $('<select multiple>')
.data('fieldName', fieldName)
//.attr('multiple')
.append($('<option>').text(text).val('').prop('disabled', true))
.append($('<option>').text('All').val('all'))
.append($table.find('tbody tr')
.toArray()
.map(tr => {
return $(tr).find(`td:eq(${colIndex})`).text();
})
.filter(text => text.trim().length > 0)
.sort()
.filter((v, i, a) => a.indexOf(v) === i)
.map(text => {
return $('<option>').text(text).val(text);
}));
$header.empty().append($select.val('').on('change', filterFn));
});
};
$.fn.initRowClasses = function(oddCls, evenCls) {
this.find('tbody tr').each(function(i) {
$(this).toggleClass(oddCls, i % 2 == 0).toggleClass(evenCls, i % 2 == 1);
});
};
$.fn.updateRowClasses = function(oddCls, evenCls) {
this.find('tbody tr:visible:even').addClass(oddCls).removeClass(evenCls);
this.find('tbody tr:visible:odd').addClass(evenCls).removeClass(oddCls);
};
})(jQuery);
$('#myTable').initRowClasses('odd', 'even');
$('.dropdown-header').tableFilterHeaders(filterText);
function filterText(e) {
let $filter = $(e.target),
$table = $filter.closest('table'),
$filters = $table.find('.dropdown-header select'),
filterObj = $filters.toArray().reduce((obj, filter) => {
let $filter = $(filter);
return Object.assign(obj, { [$filter.data('fieldName')] : $filter.val() });
}, {});
if ($filter.val() === 'all') {
$filter.val('')
}
$table.find('tbody tr').each(function() {
$(this).toggle($(this).find('td').toArray().every(td => {
let $td = $(td), fieldName = $td.attr('data-field-name');
if (fieldName != null) {
return filterObj[fieldName] === null ||
filterObj[fieldName] === '' ||
filterObj[fieldName] === 'all' ||
filterObj[fieldName] === $td.text();
}
return true;
}));
});
$table.updateRowClasses('odd', 'even');
}
</script>

When we use multi selection then the value will be in array, So the filter function will be,
$table.find('tbody tr').each(function () {
$(this).toggle($(this).find('td').toArray().every(td => {
let $td = $(td), fieldName = $td.attr('data-field-name');
if (fieldName != null) {
if (Array.isArray(filterObj[fieldName])) {
return filterObj[fieldName].length === 0 ||
filterObj[fieldName].indexOf('all') >= 0 ||
filterObj[fieldName].indexOf($td.text()) >= 0;
}
return filterObj[fieldName] === null ||
filterObj[fieldName] === '' ||
filterObj[fieldName] === 'all' ||
filterObj[fieldName] === $td.text();
}
return true;
}));
});

Related

How to sort by rows containing words and numbers in javascript

Newbie here how can I sort all of the following table row attach an onclick listener on the header after it is displayed.
ID
Name
Inventory Volume
1
Rachel
Data is not enough
2
Ross
100
3
Monica
1
4
Connor
Data is not enough
5
Dustin
-5
into this sorting example is in descending, the words should be the last.
ID
Name
Inventory Volume
2
Ross
100
3
Monica
10
5
Dustin
-5
1
Rachel
Data is not enough
4
Connor
Data is not enough
But I also want the other columns to be sorted as well and the other columns to have the function to sort as well.
Tried this solution but only works for the column.
https://jsfiddle.net/7wnke5q2/
function sortData(data, method) {
let lessData = 'Data Not Enough'
let lastItems = []
let sortedList;
if (method == 'descending') {
sortedList = data.sort((a, b) => {
return a - b
})
} else if (method == 'ascending') {
sortedList = data.sort((a, b) => {
return b - a
})
}
for (let i = 0; i < sortedList.length; i++) {
if (sortedList[i] == lessData) {
let item = sortedList[i]
sortedList.splice(i, 1)
sortedList.push(item)
}
}
sortedList = sortedList.concat(lastItems)
return sortedList
}
Could you please help me out. Thanks in advance!
If i understand, you need all "Data Not Enough" at the end. So, it can works:
function sortData(data, method) {
let lessData = 'Data Not Enough'
let sortedList;
sortedList = data.sort((a, b) => {
if(a=='Data Not Enough')
return 1
if(b=='Data Not Enough')
return -1
return method=='ascending'?a-b:b-a
})
return sortedList
}
something like that ?
just click on header columns to sort the table
const
myTableHead = document.querySelector('#my-table thead')
, myTableHead_TH = document.querySelectorAll('#my-table thead th')
, myTableBody = document.querySelector('#my-table tbody')
, myTableBody_TR = [...document.querySelectorAll('#my-table tbody tr')]
, sortOrder = ['','asc','desc']
, isDNE = str => str.trim() === 'Data is not enough'
;
myTableHead.onclick = ({target}) =>
{
if (!target.matches('th')) return
let idx = (sortOrder.findIndex(x=>x===target.className) +1) %3
myTableHead_TH.forEach(th=>th.className='')
target.className = sortOrder[idx]
if ( sortOrder[idx] )
{
myTableBody_TR
.sort(dynaSort(target.cellIndex, target.dataset.type, sortOrder[idx] ))
.forEach(tr=>myTableBody.appendChild(tr) )
}
}
function dynaSort( colIndex, colType, order='asc' )
{
let sortOrder = (order === 'desc') ? -1 : 1
return function(row_a,row_b)
{
let a = row_a.cells[colIndex].textContent
, b = row_b.cells[colIndex].textContent
;
if (isDNE(a) && isDNE(b)) return 0
if (isDNE(a)) return +1
if (isDNE(b)) return -1
if (colType==='str') return (a.trim().localeCompare(b.trim())) *sortOrder
return (Number(a) - Number(b)) *sortOrder
}
}
table {
border-collapse : collapse;
margin : 2em 1em;
font-family: Arial, Helvetica, sans-serif;
}
td,th {
padding : .2em .8em;
border : 1px solid darkblue;
}
th::after {
display : block;
float : inline-end;
content : '\25B7';
margin : 0 0 0 1em;
transition : 180ms;
color : transparent;
}
th.asc::after {
transform : rotate(-90deg);
color : whitesmoke;
}
th.desc::after {
transform : rotate(+90deg);
color : whitesmoke;
}
thead {
background : #437c97;
color : whitesmoke;
cursor : pointer;
}
<table id="my-table" >
<thead>
<tr>
<th data-type="num">ID</th>
<th data-type="str">Name</th>
<th data-type="num">Inventory Volume</th>
</tr>
</thead>
<tbody>
<tr> <td>1</td> <td>Rachel</td> <td>Data is not enough</td> </tr>
<tr> <td>2</td> <td>Ross</td> <td> 100 </td> </tr>
<tr> <td>3</td> <td>Monica</td> <td> 1 </td> </tr>
<tr> <td>4</td> <td>Connor</td> <td>Data is not enough</td> </tr>
<tr> <td>5</td> <td>Dustin</td> <td> -5 </td> </tr>
</tbody>
</table>
This should work! Using #YamirL sort alghoritm.
function sort(e, method) {
//Get table
while ((e = e.parentElement) && !e.classList.contains("table"));
//Get rows
let rows = Array.from(e.getElementsByTagName("tr"));
//Get each value for each row
let values = rows.map(row => {
let tds = Array.from(row.getElementsByTagName("td"));
return tds.map(td => td.innerHTML);
});
/*
values is a 2D array which contains each row and column
values = [
[Name, Volume], --> The headers need to be removed
[Joey, Data Not Enough],
[Ross, -5],
[Monica, 1],
[Ben, 100],
[Chandler, Data Not Enough]
];
*/
values.shift(); //remove headers
// Now we need to sort the array by volume
values.sort((a, b) => {
var exception = "Data Not Enough";
if(a[1] == exception)
return 1;
if(b[1] == exception)
return -1;
return method == 'ascending' ? a[1] - b[1] : b[1] - a[1];
});
/******* Put sort values on table *************/
// Get body
let body = e.getElementsByTagName("tbody")[0];
// Erase Body
body.innerHTML = "";
// Iterate each row
values.forEach(row => {
// Create new row element
let tr = document.createElement("tr");
// Iterate each column
row.forEach(val => {
// Create new value
let td = document.createElement("td");
// Append values
td.append(val);
tr.append(td);
});
// Append row to body
body.append(tr);
});
}
Here it is a snippet to try the complete code, I added a <tbody> to the table.
function sort(e, method) {
while ((e = e.parentElement) && !e.classList.contains("table"));
let rows = Array.from(e.getElementsByTagName("tr"));
let values = rows.map(row => {
let tds = Array.from(row.getElementsByTagName("td"));
return tds.map(td => td.innerHTML);
});
values.shift();
values.sort((a, b) => {
var exception = "Data Not Enough";
if(a[1] == exception)
return 1;
if(b[1] == exception)
return -1;
return method == 'ascending' ? a[1] - b[1] : b[1] - a[1];
});
let body = e.getElementsByTagName("tbody")[0];
body.innerHTML = "";
values.forEach(row => {
let tr = document.createElement("tr");
row.forEach(val => {
let td = document.createElement("td");
td.append(val);
tr.append(td);
});
body.append(tr);
});
}
.clickable {
cursor: pointer;
}
.clickable:hover {
opacity: 0.7;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<table class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col" class="clickable" onclick='sort(this, "descending")'>Volume</th>
</tr>
</thead>
<tbody>
<tr>
<td>Joey</td>
<td>Data Not Enough</td>
</tr>
<tr>
<td>Ross</td>
<td>-5</td>
</tr>
<tr>
<td>Monica</td>
<td>1</td>
</tr>
<tr>
<td>Ben</td>
<td>100</td>
</tr>
<tr>
<td>Chandler</td>
<td>Data Not Enough</td>
</tr>
</tbody>
</table>

HTML Table Filtering/Selection

I have an HTML table that has some static data and some from MySQL. It is currently filtering properly, what I need help is adding the "yes" and "no" selections to the selection list. These are just test values, they are being read from MySQL. I am unable to figure out what values to insert here to add values from MySQL to the selection list. Any assistance will be appreciated! Thank you
.append($table.find('tbody tr')
<!DOCTYPE html>
<html lang="en">
<link rel="stylesheet" href="/stylesheets/style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<head>
<meta charset="utf-8">
<title>Filter</title>
</head>
<script>
$.ajax({
url: 'http://localhost:7003/getTable',
type: "get",
dataType: "json",
success: function(data) {
drawTable(data);
}
});
function drawTable(data) {
for (var i = 0; i < data.length; i++) {
drawRow(data[i]);
}
}
</script>
</body>
</html>
<table id="myTable" class="table table-striped">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th class="dropdown-header">Age</th>
<th>Email</th>
<th class="dropdown-header">Gender</th>
<th class="dropdown-header">Term</th>
<th class="dropdown-header">Enrolled</th>
</tr>
</thead>
<tbody>
<script>
function drawRow(rowData) {
var row = $("<tr />")
$("#myTable").append(row);
row.append($('<td>' + rowData.County + '</td>'));
row.append($('<td>' + rowData.County + '</td>'));
row.append($('<td>').attr('data-field-name', 'age').text(rowData.County));
row.append($('<td>' + rowData.County + '</td>'));
row.append($('<td data-field-name="gender">' + rowData.County + '</td>'));
row.append($('<td data-field-name="term">' + rowData.County + '</td>'));
row.append($('<td data-field-name="enrolled">' + rowData.County + '</td>'));
}
</script>
<tr>
<td>John</td>
<td>Smith</td>
<td data-field-name="age">15</td>
<td>123</td>
<td data-field-name="gender">Male</td>
<td data-field-name="term">Summer2017</td>
<td data-field-name="enrolled">Fall2018</td>
</tr>
<tr>
<td>Jane</td>
<td>Doe</td>
<td data-field-name="age">16</td>
<td>456</td>
<td data-field-name="gender">Female</td>
<td data-field-name="term">Fall2018</td>
<td data-field-name="enrolled">Fall2019</td>
</tr>
<tr>
<td>Bobby</td>
<td>Adams</td>
<td data-field-name="age">15</td>
<td>789</td>
<td data-field-name="gender">Male</td>
<td data-field-name="term">Spring2019</td>
<td data-field-name="enrolled">Fall2018</td>
</tr>
<tr>
<td>Sarah</td>
<td>Lee</td>
<td data-field-name="age">15</td>
<td>456</td>
<td data-field-name="gender">Female</td>
<td data-field-name="term">Fall2018</td>
<td data-field-name="enrolled">Fall2018</td>
</tr>
</tbody>
</table>
<script>
(function($) {
$.fn.tableFilterHeaders = function(filterFn) {
this.each((index, header) => {
let $header = $(header),
$table = $header.closest('table'),
text = $header.text(),
colIndex = $header.closest('th').index(),
fieldName = $header.attr('data-field-name') || text.toLowerCase(),
$select = $('<select>')
.data('fieldName', fieldName)
.append($('<option>').text(text).val('').prop('disabled', true))
.append($('<option>').text('All').val('all'))
.append($table.find('tbody tr')
.toArray()
.map(tr => {
return $(tr).find(`td:eq(${colIndex})`).text();
})
.filter(text => text.trim().length > 0)
.sort()
.filter((v, i, a) => a.indexOf(v) === i)
.map(text => {
return $('<option>').text(text).val(text);
}));
$header.empty().append($select.val('').on('change', filterFn));
});
};
$.fn.initRowClasses = function(oddCls, evenCls) {
this.find('tbody tr').each(function(i) {
$(this).toggleClass(oddCls, i % 2 == 0).toggleClass(evenCls, i % 2 == 1);
});
};
$.fn.updateRowClasses = function(oddCls, evenCls) {
this.find('tbody tr:visible:even').addClass(oddCls).removeClass(evenCls);
this.find('tbody tr:visible:odd').addClass(evenCls).removeClass(oddCls);
};
})(jQuery);
$('#myTable').initRowClasses('odd', 'even');
$('.dropdown-header').tableFilterHeaders(filterText);
function filterText(e) {
let $filter = $(e.target),
$table = $filter.closest('table'),
$filters = $table.find('.dropdown-header select'),
filterObj = $filters.toArray().reduce((obj, filter) => {
let $filter = $(filter);
return Object.assign(obj, { [$filter.data('fieldName')] : $filter.val() });
}, {});
if ($filter.val() === 'all') {
$filter.val('')
}
$table.find('tbody tr').each(function() {
$(this).toggle($(this).find('td').toArray().every(td => {
let $td = $(td), fieldName = $td.attr('data-field-name');
if (fieldName != null) {
return filterObj[fieldName] === null ||
filterObj[fieldName] === '' ||
filterObj[fieldName] === 'all' ||
filterObj[fieldName] === $td.text();
}
return true;
}));
});
$table.updateRowClasses('odd', 'even');
}
</script>
Not showing yes and no options.
Your filtering logic and odd/even row coloring logic is called BEFORE the data returns from your ajax even though it appears AFTER on the page/code. This is how async methods work.
You need to call the header and coloring logic inside the drawTable() function after, of course, you are done drawing the table... like this:
function drawTable(data) {
for (var i = 0; i < data.length; i++) {
drawRow(data[i]);
}
$('#myTable').initRowClasses('odd', 'even');
$('.dropdown-header').tableFilterHeaders(filterText);
}
Make sure to remove the foloowing 2 lines of code:
$('#myTable').initRowClasses('odd', 'even');
$('.dropdown-header').tableFilterHeaders(filterText);
from your code, wherever elsewhere they appear. Leaving them will not break anything, it will just run multiple times unnecessary.

sorting html table with jquery

I have a table in html, I have set for each td an id that I will need to sort the table with a Jquery code.
Sorting works with the FireFox browser, but with Chrome it does not work ... do you know how to help me?
$(function() {
$(".table-user-th").click(function() {
var o = $(this).hasClass('asc') ? 'desc' : 'asc';
$('.table-user-th').removeClass('asc').removeClass('desc');
$(this).addClass(o);
var colIndex = $(this).prevAll().length;
var tbod = $(this).closest("table").find("tbody");
var rows = tbod.find("tr");
rows.sort(function(a, b) {
var A = $(a).find("td").eq(colIndex).attr('id');;
var B = $(b).find("td").eq(colIndex).attr('id');;
if (!isNaN(A)) A = Number(A);
if (!isNaN(B)) B = Number(B);
return o == 'asc' ? A > B : B > A;
});
$.each(rows, function(index, ele) {
tbod.append(ele);
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table border="1">
<thead>
<tr>
<th class="table-user-th">Firstname</th>
<th class="table-user-th">Lastname</th>
</tr>
</thead>
<tbody>
<tr>
<td id="Mark">Mark</td>
<td id="Red">Red</td>
</tr>
<tr>
<td id="Nick">Nick</td>
<td id="Sid">Sid</td>
</tr>
<tr>
<td id="Alex">Alex</td>
<td id="Nirv">Nirv</td>
</tr>
</tbody>
</table>
It seems like there is no purpose of using ids here.
Actually the problem was in you sort function. It should return not just true/false but the numeric difference between two values. As usual it is return -1/0/1
So here I wrote comparator func that does just that. And depending on sort type I just multiply it on -1 or 1.
I've also refactored a little bit your code not to use classes or ids. Using jquery you can use data method that stores data on element by key/value.
$(function() {
function cmp(a,b) {return a < b ? 1 : a > b ? -1 : 0}
$(".sortable-table").on('click', 'th', function() {
var th = $(this);
var colIndex = th.data('column');
if(typeof colIndex === 'undefined') {
return;
}
var sortType = th.data('sort') === 'asc' ? 'desc' : 'asc';
th.data('sort', sortType);
var table = $(this).closest("table");
table.find('thead th').removeClass('asc desc');
th.addClass(sortType);
var tbody = table.find("tbody");
var rows = tbody.find("tr");
rows.sort(function(a, b) {
var A = $(a).find("td").eq(colIndex).text();
var B = $(b).find("td").eq(colIndex).text();
return cmp(A,B) * (sortType === 'asc' ? -1 : 1);
});
$.each(rows, function(index, ele) {
tbody.append(ele);
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table border="1" class="sortable-table">
<thead>
<tr>
<th data-column="0">Firstname</th>
<th data-column="1">Lastname</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mark</td>
<td>Red</td>
</tr>
<tr>
<td>Nick</td>
<td>Sid</td>
</tr>
<tr>
<td>Alex</td>
<td>Nirv</td>
</tr>
</tbody>
</table>
Update
Added
var table = $(this).closest("table");
table.find('thead th').removeClass('asc desc');
th.addClass(sortType);

dataTable search individual with Footer callback to sum column currency

I trying to add to table search individual with Footer callback to sum currency but I can't write the correct code.
html
<table id="example">
<thead>
<tr>
<th>Rendering engine</th>
<th>Browser</th>
<th>Platform(s)</th>
<th>Engine version</th>
<th>CSS grade</th>
<th>price</th>
</tr>
</thead>
<tfoot class='footer'>
<tr>
<th>Rendering engine</th>
<th>Browser</th>
<th>Platform(s)</th>
<th>Engine version</th>
<th>CSS grade</th>
<th>price</th>
</tr>
</tfoot>
<tfoot class='custo'>
<tr >
<th colspan=5 style=text-align:right>Total:</th>
<th></th>
</tr>
</tfoot>
<tbody>
<tr>
<td>Trident</td>
<td>Internet Explorer 4.0</td>
<td>Win 95+</td>
<td> 4</td>
<td>X</td>
<td>R$ 1.000,00</td>
</tr>
<tr>
<td>Trident</td>
<td>Internet Explorer 5.0</td>
<td>Win 95+</td>
<td>5</td>
<td>C</td>
<td>R$ 2.000,00</td>
</tr>
<tr>
<td>Trident</td>
<td>Internet Explorer 5.5</td>
<td>Win 95+</td>
<td>5.5</td>
<td>A</td>
<td>R$ 500,00</td>
</tr>
</tbody>
JS
/* add input text for table footer */
$('#example tfoot.footer th').each( function () {
var title = $(this).text();
$(this).html( '<input type=\"text\"/>' );
});
/* add the sum of currency */
var table = $('#example').DataTable({
// code for footerCallback goes here but its not working
'footerCallback': function ( row, data, start, end, display ) {
var api = this.api(), data;
var intVal = function ( i ) {
return typeof i === 'string' ?
i.replace(/[\R$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
total = api
.column( 5 )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
pageTotal = api
.column( 5, { page: 'current'} )
.data()
.reduce( function (a, b) {
return intVal(a) + intVal(b);
}, 0 );
$( api.column( 5 ).custo() ).html(
'$'+pageTotal +' ( $'+ total +' total)'
);
}
});
/* make the search indvidual when keyup change. */
table.columns().every( function () {
var that = this;
$( 'input', this.footer() ).on( 'keyup change', function () {
if ( that.search() !== this.value ) {
that
.search( this.value )
.draw();
}
});
});
Here the example without the sum currency: http://jsfiddle.net/minamagdy666/e88yrhaj/13/
the example that I want to use for sum currency on that link: enter link description here
Thanks
do this example :
const Table = $('#foo').DataTable({
. . . . . .,
. . . . . .,
drawCallback: function(){
Table.columns(5, {
page: 'current'
}).every(function() {
var sum = this
.data()
.reduce(function(a, b) {
var x = parseFloat(a) || 0;
var y = parseFloat(b) || 0;
return x + y;
}, 0);
console.log(sum);
$(this.footer()).html(sum);
});
}
});
in this case, the column is column number 5

sorting table using template

I have knockout binding on table with columns. I was trying to achieve table sorting for each column.
The view looks like:
<table id="notes" class="notes_table">
<tr class="head">
<th data-bind='click: function() { SortItems("CreatedDate")}'>
<span>Date</span>
</th>
<th data-bind='click: function() { SortItems("Type")}'>
<span>Type</span>
</th>
<th data-bind='click: function() { SortItems("Category")}'>
<span>Category</span>
</th>
<th data-bind='click: function() {SortItems("AddedBy")}'>
<span>Added by</span>
</th>
</tr>
<tbody data-bind="template: { name: 'StudentNote', foreach: notes }"></tbody>
</table>
<script type="text/html" id="StudentNote">
<tr class="even">
<td><span data-bind="text: CreatedDate"></span></td>
<td><span data-bind="text: Type"></span></td>
<td><span data-bind="text: Category"></span></td>
<td><span data-bind="text: AddedBy"></span></td>
</tr>
</script>
and the javascript is like:
function notesViewModel() {
var _this = {};
_this.colName = "CreatedDate";
_this.sortOrder = "desc";
_this.notes = ko.observableArray();
_this.SortItems = function (ColumnName) {
var newNotes = _this.notes();
if (_this.sortOrder === "desc") {
this.notes(newNotes.sort(notesViewModel._getSortFunction = function (a, b) {
_this.sortOrder = "asc";
return a[ColumnName] < b[ColumnName] ? -1 : 1;
}));
} else {
this.notes(newNotes.sort(notesViewModel._getSortFunction = function (a, b) {
_this.sortOrder = "desc";
return a[ColumnName] > b[ColumnName] ? -1 : 1;
}));
}
};
ko.applyBindings(_this, $("body").get(0));
return _this;
Even though it does sorting, it just switches between ascending and descending sort on each of the column, but not recognises which column it is sorting.. How to do sorting by each column..
Try this:
function notesViewModel() {
var _this = {};
_this.colName = "CreatedDate";
_this.sortOrder = 1;
_this.notes = ko.observableArray();
_this.SortItems = function (ColumnName) {
if(ColumnName == _this.colName)
_this.sortOrder = _this.sortOrder * -1;
else
_this.colName = ColumnName;
_this.notes.sort(function (a, b) {
return (a[ColumnName] < b[ColumnName] ? -1 : 1) * _this.sortOrder;
});
};
ko.applyBindings(_this, $("body").get(0));
return _this;
}

Categories