npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

table-builder

v2.1.1

Published

Create HTML-tables from JSON

Downloads

4,316

Readme

table-builder Build Status

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)
  1. Copy built UMD module: cp node_modules/table-builder/tablebuilder.js dist/tablebuilder.js

  2. 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 = [/* see data section above */];

// You can put key-value pairs if you strongly want keep headers order:
// [['name', 'User name'], ['age', 'User age'], ['link', 'Homepage']]
var headers = { "name" : "User name", "age": "User age", "link": "Homepage" };

var Table = require('table-builder');
console.log(
  (new Table({'class': 'some-table'}))
    .setHeaders(headers) // see above json headers section
    .setData(data) // see above json data section
    .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))

example result

API

Prisms

Prism are callbacks-preprocessors for specified fields.

var data = [ // Look the previous case differences: link format changed and name splitted into firstname and surname
  { "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) {
  // Calc average age
  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

// Show table replacer block if data set is empty
// ...
table
  // ...
  .render()
  || 'Data collection is empty!';

Client side sorting, filtering

You can use list.js with table builder.

TODO

  • [x] Unit tests, CI
  • [x] Decompose methods
  • [ ] More unit tests
  • [ ] Run building and another activity only in the render() method, push intermediate methods into preordered list
  • [ ] Framefork agnostic: possibility to use with React and another frameworks
    • tagBuilder as a dependency injection (for compatibility with either: innerHTML, createElement, React.Component)
  • [ ] Internal type constructors with asserts
  • [ ] Data model, changing/accessing data api
  • [ ] Client-side filters, multisort s
  • [ ] Plural versions of methods: setPrisms, setTotals
  • [ ] Plugins system (call hooks for different cells)
  • [ ] N/A maps
  • [ ] Escaping

See also another solutions

React based:

Framework agnostic:

  • suggestions are welcome