Json-table is a fully customizable client-side table renderer for displaying json data. At its core, it supports generating a table backed by an array of javascript objects (via optional hooks for generating the table, row, and cell components) and primitive operations on the underlying data (removal, insertion, and sort) that automatically propagate to the DOM.
$(element).table(data, columns, format);
columns is an array of keys representing the columns of the table, which defaults to the set of all keys present in data when omitted. format is an optional object providing one or more of three formatting hooks:
var format = {
table: function(columns, hooks) {
// columns is the array of columns provided or generated
// hooks is this format object
return [outerNode, innerNode];
},
row: function(value, index) {
// value is the object from data at index
return [outerNode, innerNode];
},
cell: function(key, value, index, row) {
// index is the column number
// row is the parent row's data object
return outerNode;
}
};
These hooks return one or two DOM nodes: outerNode is attached to the parent component's innerNode. The resulting json-table supports the following methods. All but get are chainable.
get(row, column) returns value at cell, or object at row if column is omitted, or all data if neither is providedinsert(object, index) inserts a row at index given its object data, or appends if index is omittedinsertAll(objects, index) inserts all items in an array of objects, or appends if index is omittedremove(index) removes row at indexsort(compare) sorts rows in table with the given comparison functionThe most basic example simply generates a table whose columns are the keys of the data array's objects.
var data = [
{Company: 'Yahoo', CEO: 'Marissa Mayer', Founded: '1994', Headquarters: 'Sunnyvale, CA'},
{Company: 'Google', CEO: 'Larry Page', Founded: '1998', Headquarters: 'Mountain View, CA'},
{Company: 'Facebook', CEO: 'Mark Zuckerberg', Founded: '2004', Headquarters: 'Menlo Park, CA'},
{Company: 'Apple', CEO: 'Tim Cook', Founded: '1976', Headquarters: 'Cupertino, CA'}
];
$('#basic').table(data);
This example adds sorting functionality to the table by adding click handlers to its th elements via a custom cell formatter.
var table = $('#sorting').table(data, null, {
cell: (function(lastSorted, order) {
// keep track of last sorted header element and order
return function(value, index, key, row) {
// row is null for header cells
var elem = $(row ? '<td>' : '<th>').text(value);
if (!row) elem.click(function() {
if (lastSorted) lastSorted.className = '';
order = this == lastSorted ? -order : 1;
(lastSorted = this).className = order > 0 ? 'asc' : 'desc';
table.sort(function(a, b) {
return order * a[value].localeCompare(b[value]);
});
});
return elem[0];
};
})()
});
This example uses jsml to generate an editable spreadsheet with fixed columns.
var spreadsheet = $('#spreadsheet').table(data, [''].concat(Object.keys(data[0])), {
table: function(columns, hooks) {
var body, head = hooks.row(columns, -1);
return [$.jsml({table: function(table) {
return [
{thead: columns.map(function(column) {
return {th: column ? column : {className: 'menu', children: [
{span: {
className: 'edit',
title: 'Edit',
onclick: function() {
table.className = table.className == 'editing' ? '' : 'editing';
try { table.getElementsByTagName('input')[0].focus(); } catch (e) {}}}},
{span: {
className: 'add',
title: 'Add Row',
onclick: function() {
spreadsheet.insert({}); }}}]}}})},
{tbody: function(e) { body = e; }}]; }}), body]; },
cell: function(key, value, index, row) {
return $.jsml({td: key
? [{div: value}, {input: {
type: 'text',
value: value || '',
onkeyup: function(e) {
row[key] = this.previousSibling.textContent = this.value; }}}]
: {className: 'menu', children: [
{span: {
className: 'reorder',
title: 'Reorder',
onmousedown: function(e) {
var move, up, pos = spreadsheet.get().indexOf(row),
style = $('<style>* { cursor: -webkit-grabbing !important; cursor: grabbing !important; }</style>').appendTo('head'),
boundaries = Array.prototype.slice.call(this.parentNode.parentNode.parentNode.childNodes, 0, -1).map(function(tr) {
return tr.getBoundingClientRect().bottom; });
document.addEventListener('mousemove', move = function(e) {
var i = 0;
boundaries.some(function(y) { return e.clientY < y || !++i; });
if (pos != i) spreadsheet.remove(pos).insert(row, pos = i);
e.preventDefault(); });
document.addEventListener('mouseup', up = function() {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', up);
style.remove(); }); }}},
{span: {
className: 'delete',
title: 'Delete',
onclick: function() {
spreadsheet.remove(spreadsheet.get().indexOf(row)); }}}]}}); }});