tablefiniti

2.0.9 • Public • Published

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
    }
  }
}

The `childSorting` is the only inner object function of the `config` object. It has a default value of `null` and takes a function as an acceptable value. The function itself is the main param of`Array.sort()`, for which is the reason the function has 2 props that has to be compared and return 1 of 3 possible values, `[0,1,-1]`. The `childSorting()` is a function that is run over an iteration made by `Array.sort()` therefore `propA` and `propB` will mutate is value on each iteration and if the results (depends on how the user wants to sort the properties inside the child element of the row) is equal then a `0` is returned, if it is less (will go first in `desc` order) then a `-1` is returned and it is is greater a `1` is returned.

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.

Package Sidebar

Install

npm i tablefiniti

Weekly Downloads

10

Version

2.0.9

License

ISC

Unpacked Size

59.9 kB

Total Files

11

Last publish

Collaborators

  • shiondev
  • vincentzierigendf
  • pbcoleman
  • mistermoe
  • hrgoulden
  • travis.roberts2