table-builder
Create HTML tables from a JSON in a both Node.js (0.10+) and browsers enviroments.
Installation
yarn add --production table-builder
or
npm i --production table-builder
--production
flag skips devDependencies of the table-builder (testing framework).
Usage
node.js and webpack
import TableBuilder from 'table-builder'
browser (without build tool)
-
Copy built UMD module:
cp node_modules/table-builder/tablebuilder.js dist/tablebuilder.js
-
Insert tag:
<script src="/dist/tablebuilder.js"></script>
Simple Example
Each object represents one row in the data array.
[
{ "name":"Larry Wall", "age":57, "link": "<a href='http://www.wall.org/~larry/'>www.wall.org/~larry/</a>" },
{ "name":"Bill Gates", "age":56, "link": "<a href='http://www.microsoft.com'>www.microsoft.com</a>" },
{ "name":"Daffy Duck", "age":75, "link": "" }
]
var data = [];
var headers = { "name" : "User name", "age": "User age", "link": "Homepage" };
var Table = require('table-builder');
console.log(
(new Table({'class': 'some-table'}))
.setHeaders(headers)
.setData(data)
.render()
);
Rendered to:
<table class='some-table'>
<thead> <tr> <th>User name</th> <th>User age</th> <th>Homepage</th> </tr> </thead>
<tbody>
<tr>
<td class="name-td">Larry Wall</td>
<td class="age-td">57</td>
<td class="link-td"><a href="http://www.wall.org/~larry/">www.wall.org/~larry/</a></td>
</tr>
<tr>
<td class="name-td">Bill Gates</td>
<td class="age-td">56</td>
<td class="link-td"><a href="http://www.microsoft.com">www.microsoft.com</a></td>
</tr>
<tr>
<td class="name-td">Daffy Duck</td>
<td class="age-td">75</td>
<td class="link-td"></td>
</tr>
</tbody>
</table>
Example of simple scrapper with tablebuilder result representation
const process = require('process')
const TableBuilder = require('table-builder')
const table = new TableBuilder({class: 'avito'})
const headers = {price: 'Price', title: 'Title'}
const thrw = require('throw')
const fetch = require('isomorphic-fetch')
const getHttp = (uri) => fetch(uri).then(r => r.status >= 400 ? thrw (r.status) : r.text())
const parseHtml = html => require('jsdom').jsdom(html)
const uri = process.argv[2] || 'https://www.avito.ru/moskva/telefony/iphone?q=iphone+se'
const retreiveData = (document) => Array.from(document.querySelectorAll('.js-catalog_after-ads .item')).map(i=>({title:i.querySelector('.title'), price:i.querySelector('.about')})).map(({title,price})=>({title:title.textContent.trim(),price:price.textContent.trim()}))
const main = () =>
getHttp(uri)
.then(html => parseHtml(html))
.then(document => retreiveData(document))
.then(data => table.setHeaders(headers).setData(data).render())
const style = `<style>body { text-align: center; } .avito {width: 100%;} thead { text-align: left; } .price-td { text-align: right; }</style>`
main().then(r=>console.log(style, r))
API
Prisms
Prism are callbacks-preprocessors for specified fields.
var data = [
{ "firstname":"Larry", "surname":"Wall", "age":57, "link": "www.wall.org/~larry/" },
{ "firstname":"Bill", "surname":"Gates", "age":56, "link": "www.microsoft.com" },
{ "firstname":"Daffy", "surname":"Duck", "age":75, "link": "" }
];
(new Table({'class': 'some-table'}))
.setPrism('link', function (cellData) {
return cellData && '<a href="http://'+cellData+'">'+cellData+'</a>' || 'N/A';
})
.setPrism('name', function (cellData, row) {
return row.surname + ' ' + row.firstname;
})
.setHeaders({ "name": "User name", "age": "User age", "link": "Homepage" })
.setData(data)
.render()
Render output is equal the previous case.
Also, prism callback may return {presentation: '...', raw: '...'}
object
for splitting html wrapped cell values and raw values.
For example, raw values uses in totals.
Totals
See following code:
table.setTotal('age', function (columnCellsCollection, rowsCollection) {
return Math.round(
columnCellsCollection
.reduce(function (prev, val) { return +prev + val; })
/ columnCellsCollection.length
);
});
It adds tfoot
in the table with average age:
<tfoot><tr><td></td><td></td><td>62</td></tr></tfoot>
Grouping
Grouping fields util (setGroup
).
table
.setGroup('product_category', function (value, recordsCount, totals) {
})
.render();
Group removes the field (product_category
) from the table
and adds row-separators with the field's values (group names). and referenced items.
Body of the setGroup callback may contains processor of group name.
Additionaly processor may use the group's recordsCount
and totals
collection for group
if setTotal
for whole table have installed.
If callback is not defined then tableBuilder uses group name without processing, as is.
Empty data collection
table
.render()
|| 'Data collection is empty!';
Client side sorting, filtering
You can use list.js with table builder.
TODO
See also another solutions
React based:
Framework agnostic: