Git Product home page Git Product logo

table-builder's Introduction

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

  • Unit tests, CI
  • 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
  • Plural versions of methods: setPrisms, setTotals
  • Plugins system (call hooks for different cells)
  • N/A maps
  • Escaping
  • Complex 2-level headers feature
  • Sticky headers feature
  • Vertical header feature
  • Simplify prisms api: callback must returns presentation data only instead of {raw, presentation}

See also another solutions

React based:

  • react-data-grid - I did not use it still
  • react-table - I revealed problems with custom styles and stability
  • suggestions are welcome

Framework agnostic:

  • suggestions are welcome

table-builder's People

Contributors

a-x- avatar bsb002-flash-tester avatar pixeloution avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

table-builder's Issues

Remove tfoot if not needed

Thanks for this library! I was thinking of building it myself but you've gotten off to a good start.

I'd like to contribute, but just have a small request for now so I'll paste it as an issue.

In your buildFooter function, if no totals are used, there is a blank <tfoot></tfoot> added. This doesn't look great on tables with borders as it appears to be a blank row. Add this patch to the buildFooter function to return an empty string:

        if (content.length > 2) {
          return '<tfoot><tr>' + content.join('') + '</tr></tfoot>';
        } else {
          return ''
        }

Not working in browser

It does not work in browser, I have added the tablebuilder.js to my assets, copied from node_modules as you describe. I get Uncaught ReferenceError: Table is not defined
Call is (new Table({ 'class': 'some-table' })) .setHeaders(headers).setData(data).render()

Preserve property keys as cell class names

This is such a beautiful library, thank you. Noticed that the class names for the td cells substitue underscores in the property name to hyphens.

In my data, the property name is mla_name but in the html I can see the td class set to mla-name-td

screen shot 2018-11-15 at 4 36 01 pm

It would be a lot more convenient if the property name mla_name was preserved as the class names for consistency.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.