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 index
sort(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)); }}}]}}); }});