Skip to content

Instantly share code, notes, and snippets.

@kkestell
Created October 16, 2014 18:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kkestell/ade30f868bd122707628 to your computer and use it in GitHub Desktop.
Save kkestell/ade30f868bd122707628 to your computer and use it in GitHub Desktop.
/*
Basic Usage
===========
Assuming your markup looks like this:
<table id="table" class="table"></table>
<div id="pagination" class="text-center"></div>
And your JSON looks like this:
{
total: 125,
results: [
{
name: 'John Doe',
age: 40,
admin: true
},
{
name: 'Jane Doe',
age: 25,
admin: false
}
]
}
You'd initialize the table like this:
$('#table').table({
url: '/Users',
limit: 10,
pagination: '#pagination',
showPages: 5,
columns: [
{
label: 'Name',
key: 'name',
classes: 'class-here another-class'
},
{
label: 'Age',
key: 'age'
},
{
label: 'Admin',
key: 'admin',
format: function(item, val) {
return val === true ? 'Yes' : 'No';
}
}
]
});
Column Sorting
==============
To enable sorting on a column, add an allowSorting property to the column
definition. Two global options are also defined, sortBy, to control the
column to sort on by default, and sortDescending, which lets you control
the sort order.
$('#table').table({
url: '/Users',
limit: 10,
pagination: '#pagination',
sortBy: 'name',
sortDescending: false,
columns: [
{
label: 'Name',
key: 'name',
allowSorting: true
},
{
label: 'Age',
key: 'age',
allowSorting: true
},
{
label: 'Admin',
key: 'admin',
format: function(item, val) {
return val === true ? 'Yes' : 'No';
}
}
]
});
Filtering
=========
Assuming your markup looks like this:
<form id="filters">
<input type="text" name="name" />
<select name="admin">
<option value="true">Yes</option>
<option value="false">No</option>
</select>
<input type="submit" value="Filter" />
</form>
<table id="table" class="table"></table>
<div id="pagination" class="text-center"></div>
You'd initialize the table like this:
$('#table').table({
url: '/Users',
limit: 10,
listenTo: '#filters',
extraParams: function() {
return $('#filters').serializeToJS();
},
pagination: '#pagination',
columns: [
{
label: 'Name',
key: 'name'
},
{
label: 'Age',
key: 'age'
},
{
label: 'Admin',
key: 'admin',
format: function(item, val) {
return val === true ? 'Yes' : 'No';
}
}
]
});
And any time the filters form is submitted, your table will automatically
update.
The `extraParams` option takes a function which should return an object. This
object will be serialized and passed up to the server with the XHR request.
NOTE: In this example we're using `serializeToJS` which is provided by
~/Content/JS/Core/Serialization.js
*/
(function ($) {
$.fn.table = function (options) {
var settings = $.extend({
limit: 10,
showPages: 5,
sortBy: null,
sortDescending: false
}, options);
var $table = $(this);
var offset = 0;
// Build table row and header cells
function buildHead() {
var thead = '';
thead += '<thead>';
thead += '<tr>';
settings.columns.forEach(function (col) {
var classes = '';
if (typeof col.classes !== 'undefined') {
classes = col.classes;
}
if (settings.sortBy === col.key) {
thead += '<th data-key="' + col.key + '" class="active '+ classes +'">';
thead += col.label;
if (settings.sortDescending === true) {
thead += ' V';
} else {
thead += ' ^';
}
thead += '</th>';
} else {
thead += '<th data-key="' + col.key + '" class="' + classes + '">' + col.label + '</th>';
}
});
thead += '</tr>';
thead += '</thead>';
$table.find('thead').remove();
$table.prepend(thead);
}
// Build table rows and body cells
function buildBody(items) {
var tbody = '';
tbody += '<tbody>';
items.forEach(function (item) {
tbody += '<tr>';
settings.columns.forEach(function (col) {
var val = item[col.key];
var classes = '';
if (typeof col.classes !== 'undefined') {
classes = col.classes;
}
tbody += '<td class="'+ classes +'">';
if (typeof col.format === 'function') {
tbody += col.format(item, val);
} else {
tbody += val;
}
tbody += '</td>';
});
tbody += '</tr>';
});
$table.find('tbody').remove();
$table.append(tbody);
}
// Update pagination controls
function buildPagination(totalItems) {
var numPages = Math.ceil(totalItems / settings.limit),
currentPage = Math.ceil(offset / settings.limit),
ul = '';
var pages = settings.showPages;
var prevPage = Math.floor(pages / 2);
ul += '<ul class="pagination">';
// Add Left Arrow
if (currentPage > 0) {
ul += '<li><a data-page="' + (currentPage - 1) + '" href="#">&laquo;</a></li>';
} else {
ul += '<li class="disabled"><a href="#">&laquo;</a></li>';
}
if (numPages <= pages) {
for (var i = 0; i < numPages; i++) {
if (currentPage === i) {
ul += '<li class="active"><a href="#">' + (i + 1) + '</a></li>';
} else {
ul += '<li><a data-page="' + i + '" href="#">' + (i + 1) + '</a></li>';
}
}
} else {
// Display first 'x' number of links
if (currentPage < prevPage) {
for (var i = 0; i < pages; i++) {
if (currentPage === i) {
ul += '<li class="active"><a href="#">' + (i + 1) + '</a></li>';
} else {
ul += '<li><a data-page="' + i + '" href="#">' + (i + 1) + '</a></li>';
}
}
}
// Display last 'x' number of links
else if ((currentPage + 1) > (numPages - prevPage)) {
var page = (numPages - pages);
for (var i = 0; i < pages; i++) {
if (currentPage === page) {
ul += '<li class="active"><a href="#">' + (page + 1) + '</a></li>';
} else {
ul += '<li><a data-page="' + page + '" href="#">' + (page + 1) + '</a></li>';
}
page++;
}
}
// Display pages on either side of current page
else {
for (var i = 0; i < prevPage; i++) {
ul += '<li><a data-page="' + ((currentPage + 1) - (prevPage - i)) + '" href="#">' + ((currentPage + 1) - (prevPage - i)) + '</a></li>';
}
ul += '<li class="active"><a href="#">' + (currentPage + 1) + '</a></li>';
for (var i = 0; i < prevPage; i++) {
ul += '<li><a data-page="' + (currentPage + (i + 2)) + '" href="#">' + (currentPage + (i + 2)) + '</a></li>';
}
}
}
if (currentPage < numPages - 1) {
ul += '<li><a data-page="' + (currentPage + 1) + '" href="#">&raquo;</a></li>';
} else {
ul += '<li class="disabled"><a href="#">&raquo;</a></li>';
}
/*if (currentPage > 0) {
ul += '<li><a data-page="' + (currentPage - 1) + '" href="#">&laquo;</a></li>';
} else {
ul += '<li class="disabled"><a href="#">&laquo;</a></li>';
}
for (var i = 0; i < showPages; i++) {
if (currentPage === i) {
ul += '<li class="active"><a href="#">' + (i + 1) + '</a></li>';
} else {
ul += '<li><a data-page="' + i + '" href="#">' + (i + 1) + '</a></li>';
}
}
if (currentPage < numPages - 1) {
ul += '<li><a data-page="' + (currentPage + 1) + '" href="#">&raquo;</a></li>';
} else {
ul += '<li class="disabled"><a href="#">&raquo;</a></li>';
}
*/
ul += '</ul>';
$(settings.pagination).html(ul);
}
// Update table data from server
function query() {
var extraParams = {
limit: settings.limit,
offset: offset,
sortBy: settings.sortBy,
sortDescending: settings.sortDescending
};
if (typeof settings.extraParams === 'function') {
$.extend(extraParams, settings.extraParams());
}
$.ajax(settings.url, {
data: extraParams,
type: 'GET',
success: function (data, textStatus, jqXHR) {
buildBody(data.results);
if (settings.pagination !== undefined) {
buildPagination(data.total);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Error fetching data.');
}
});
}
// Listen to a form and automatically update when it's submitted
if (settings.listenTo !== undefined) {
$(settings.listenTo).submit(function (e) {
// Reset offset when filters change
offset = 0;
e.preventDefault();
query();
});
}
// Update when pagination links are clicked
if (settings.pagination !== undefined) {
$(settings.pagination).on('click', 'a', function (e) {
e.preventDefault();
var page = parseInt($(this).data('page'));
if (!isNaN(page)) {
offset = page * settings.limit;
query();
}
})
}
// Update sortBy and sortDescending when a table header is clicked
$table.on('click', 'th', function (e) {
e.preventDefault();
var sortBy = $(this).data('key');
var allowSorting = false;
settings.columns.forEach(function (col) {
if(col.key === sortBy) {
if (col.hasOwnProperty('allowSorting') === true && col.allowSorting === true) {
allowSorting = true;
}
}
});
if (allowSorting === false) return;
if (settings.sortBy === sortBy) {
settings.sortDescending = !settings.sortDescending;
} else {
settings.sortDescending = false;
settings.sortBy = sortBy;
}
buildHead();
query();
});
buildHead();
query();
return this;
};
}(jQuery));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment