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

tablefiniti

v2.0.9

Published

A react component to display information on a react js based table

Downloads

5

Readme

Tablefiniti

Tablefiniti is a table (ReactJS Component) that is adapted for the spefic needs of Datafiniti Web projects that use tables and require a variety of graphicial options, such as expandable rows, custom React Components on divisions and a form-agnostic paradigm.

Initial set up

The initial set up of Tablefiniti is quite easy. First import Tablefiniti into your React Project:

/* Dependency imports */
import React, { Component } from 'react'
import Tablefiniti from 'tablefiniti'

After that the component itself only need 3 obligatory props to work:

  • rows an array of rows in the Tablefiniti format
  • headers a simple array of strings
  • totalRecords an integer, most of the time returned by the server, that states the total amount of records that can be fetched

A simple set up of the table looks like this:

/* Dependency imports */
import React, { Component } from 'react'
import Tablefiniti from 'tablefiniti'

class SimpleTable extends Component {
  render () {
    let headers = ['Id', 'Firstname', 'Lastname']
    let rows = [{
      Id: '1',
      Firstname: 'Francisco',
      Lastname: 'Jimenez'
    }, {
      Id: '2',
      Firstname: 'Vincent',
      Lastname: 'Zierigen'
    }]
    return (
      <Tablefiniti
        rows={rows}
        headers={headers}
        totalRecords={rows.length}
      />
    )
  }
}

export default SimpleTable

Notice that for totalRecords the length of the rows is being used, but most of the time will be a number higher than the amount of the present data, as it can represent the total amount of records a query inside the server holds

Data format and types

The data that Tablefiniti consumes must be in a specific format. Let's take a look at following data:

let headers = ['Id', 'Firstname', 'Lastname']
let rows = [{
  Id: '1',
  Firstname: 'Juan',
  Lastname: 'Valdez'
}, {
  Id: '2',
  Firstname: 'Jane',
  Lastname: 'Doe'
}]

Notice that the keys on each object that represent a row, match exactly the name of a header. Tablefiniti will not render a column that does not have matching header. (Credits to: Trevor Pace for the idea of using objects to represent the rows).

So far, only strings are represented on data, but tablefiniti support various types of data. Take a look a this more complex data model:

let headers = ['Id', 'Firstname', 'Lastname', 'Link']
let rows = [{
  Id: '1',
  Firstname: 'Juan',
  Lastname: 'Valdez',
  Link: {
    type: 'link',
    data: 'Go!',
    url: '#here'
  }
}, {
  Id: '2',
  Firstname: 'Jane',
  Lastname: {
    type: 'string',
    data: 'Doe'
  },
  Link: {
    type: 'link',
    data: 'Download!',
    url: '#download'
  }
}]

Link is a type of data that generates an <a> tag with a text inside, being the data the text and the url the href used address.

Data Types

There are 3 types of data available for Tablefiniti:

String

Strings can be declared in the complex form using type and data, but it is not necesary, as strings can be interpreted by Tablefiniti in ther simple regular JS form.

Lastname: {
	type: 'string',
	data: 'Doe'
}

OR

Lastname: 'Doe'

Link

Link: {
	type: 'link',
	data: 'Download!',
	url: 'https://myawesomedomain.com/tablefinitirules:1337'
}

Compound

Compound is a group of 2 text represented as simple strings that can be displayed using the following format:

{
  type: 'compound',
  title: 'Some Title',
  subTitle: `This is a subtitle`
}

Custom

Custom is the most complex of the 3 types as it allows you to create a custom React generator that returns a React Component.

Sample of a generator function

const editButton = myID => {
  return (
    <a onClick={alert(myID)} className='btn btn-info btn-sm'>
      <span className='icon-pencil' />
    </a>
  )
}

let rows = [
...
{
  'ID': '248148',
  'Status': {
    type: 'custom',
    generator: editButton('Some Text or ID')
  },
  'Num of Records': '300',
  'Date/TimeStarted': 'May 4, 2016 at 3:15pm'
}
...
]

Hidden Rows

Tablefiniti allows you set up hidden rows that are toggable by clicking the first division of the parent object.

Row with a child element

...
 {
    'ID': '248148',
    'Num of Records': '300',
    'Date/TimeStarted': 'May 4, 2016 at 3:15pm',
    'Status': 'In Progress',
    child: {
      title: 'Criteria Selected',
      data: {
        'Source': '*walmart*',
        'SourceUrls': 'Reviews',
        'DateUpdated': '*2017-01-30*',
        'Brand': 'dell'
      }
    }
  }
...

The data keys of the child object are rendered inside of a single divison ( td ) with a colSpan equal to the amount of columns in the table.

IMPORTANT

The father object's first column corresponding value HAS to be a string for this feature to work correctly, otherwise, Tablefiniti won't process the data and will dispatch an error.

Props

Besides the 3 needed props for operation, Tablefiniti has 2 other props that can be used:

currentPage

currentPage lets the user ser manually which page should the paginator indicate the table is in. It must be a Number. This is an optional prop.

sorting

sorting lets the user override or manually place a sorting object, which should always be in the following format:

 sorting: { 
    header: '', // Must be a valid Table header
    order: '' // asc or desc
  }

This is an optional prop.

onQueryChange(query)

onQueryChange(query) is a function prop that can be passed to Tablefiniti, this function will be triggered everytime a part of Tablefiniti regarding the order of view (sorting, paging or records per page) is changed.

Example

...
  //Method on the component that holds Tablefiniti
  onQueryChange (query) {
    //Do something with the query information
  }
...
<Tablefiniti onQueryChange={this.onQueryChange} config={config} rows={rows} headers={headers} totalRecords={totalRecords} />
//Example of a complete query object sent from the callback
//Order can be `asc` or `desc`
query {
  "currentPage": 4,
  "rowsPerPage": 10,
  "sorting": {
    "header": "Type",
    "order": "asc"
  }
}

config {}

The config prop allows the user set up several configuration options to make Tablefiniti more suitable to the user's needs.

Sample of a complete configuration object

let config = {
  noDataMessage: 'There is no data available.',
  rowsPerPageVisibility: {
    up: true,
    down: false,
    expandCollapse: false
  },
  customCSS: {
    table: 'separation anxiety',
    rows: 'spiderman venom mary jane watson',
    paginator: 'maximum carnage'
  },
  nonSortableHeaders: ['Edit'],
  childSorting: (propA, propB) => {
    if (propA === 'Rank') {
      return -1
    } else {
      return 1
    }
  }
}

Example (taken from MDN):

function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

Note: rowsPerPageVisibility allows the user to hide the rowsPerPage on the paginator modules and includes a option called expandCollapse that allows a expand/collapse button to appear, this button will either expand of collapse all availble childen row (if any, if there's no children rows, nothing will happen)

This is Tablefiniti's default config inner JSON

{
rowsPerPageVisibility: {
  up: true,
  down: true,
  expandCollapse: false// Option that displays the expand/collapse controller
  						// it overrides the rowsPerPageVisibility if present
},
customCSS: {
  table: '',
  rows: '',
  paginator: ''
},
nonSortableHeaders: [],
childSorting: null // Function that replaces Array.sort()
} // Config object, taken from props

No data provided

When Tablefiniti recives no data or the data was not fetched, Tablefiniti will display the message inside noDataMessage on the configuration object. It will render a simple table with the provided headers and the message.

If no headers are provided, then Id and Name will appear as default headers.

Examples

Simple Table

This is a simple example of how to set up Tablefiniti with the bare minimum using the 3 data types:

// Simple example

/* Dependency imports */
import React, { Component } from 'react'
import Tablefiniti from '../Tablefiniti.jsx'

class SimpleTable extends Component {
  constructor (props) {
    super(props)
    this.state = {
      rows: [],
      headers: []
    }
    this.editButtonGenerator = this.editButtonGenerator.bind(this)
  }

  componentDidMount () {
    let headers = ['ID', 'Num of Records', 'Date/TimeStarted', 'Status']
    let rows = [
      {
        'ID': '248148',
        'Num of Records': '300',
        'Date/TimeStarted': 'May 4, 2016 at 3:15pm',
        'Status': 'In Progress',
        child: {
          title: 'Criteria Selected',
          data: {
            'Source': '*walmart*',
            'SourceUrls': 'Reviews',
            'DateUpdated': '*2017-01-30*',
            'Brand': 'dell'
          }
        }
      },
      {
        'ID': '248148',
        'Status': {
          type: 'link',
          data: 'Download Records',
          url: '#downloads_records'
        },
        'Num of Records': '300',
        'Date/TimeStarted': 'May 4, 2016 at 3:15pm'
      },
      {
        'ID': '248148',
        'Status': {
          type: 'custom',
          generator: this.editButtonGenerator('Hey hey')
        },
        'Num of Records': '300',
        'Date/TimeStarted': 'May 4, 2016 at 3:15pm'
      }
    ]
    this.setState({rows, headers})
  }

  editButtonGenerator (id) {
    return (
      <a onClick={e => alert(`This would edit id: ${id}`)} className='btn btn-info btn-sm'>
        <span className='icon-pencil' />
      </a>
    )
  }

  render () {
    let { rows, headers } = this.state

    if (rows.length === 0 || headers === 0) {
      return (<div />)
    }

    return (
      <div style={{margin: 100}}>
        <Tablefiniti
          rows={rows}
          headers={headers}
          totalRecords={rows.length}
      />
      </div>
    )
  }
}

export default SimpleTable

Explicit Example

An explicit example that implements all Tablefiniti's options, server simulation and a search form can be seeing here.