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

gridact

v4.0.0

Published

Your Excellent React Grid Component

Downloads

6

Readme

Gridact

Your Excellent React Grid Component

Gridact is React component for displaying large datasets in table supporting

  • filtering
  • sorting
  • paging
    • custom page lengths with initial set
  • custom row classes based on row data
  • individual columns definitions
    • column name
    • sortable, editable,
    • hidden, width, table head class
    • custom cell rendering (based on cell and row data)
    • custom cell class rendering based on row data
  • inline editing with server side processing
    • edit cells
    • add and remove rows
    • custom allowed values and characters
    • error messages

##Live demo on CodeSandBox

Please open the project in window (https://89khh.codesandbox.io/), not in CodeSandBox browser, does not work.

##Changelog 3.1.0 (2022-08-18)

  • optimized version, a lot of changes in code, coded splitted into more modules for better readability.
  • added cross-application gridactContext, which made it much better administratable.
  • primaryKey property no longer user, module calculates its own.

##Changelog 2.5.0

  • new format of data from edit, simplier {newValue, column, row} From Row you can find whatever identification you need. Remove primary_key property of GridAct - you do not need this anymore

##Changelog 2.1.0

  • editable option in column definitions can now be function (e.g. you want to edit only if some condition is met)
  • enhanced sorting, corrected sort of empty (null) values
  • title option now available in columns definition

##Changelog 2.0.0

  • Further optimized re-render evaluation on row (propsAreEqual.js)
  • Code readability improved
  • Access to filtered rows, so you can e.g. calculate total sums to your table header (look at setFilteredData prop)

##Changelog 1.0.0

  • Many small bugs fixed
  • Changed Icons to Font Awesome
  • initial sort (initSort) now possible
  • mainTableContainerClass for styling whole table container

GridAct

I have done my best to optimize rendering, so the work is for user very good with rendering displayed table with 2000 cells (100 rows with 20 columns) in ~200 ms or 10000 cells in ~800 ms. (Change page to page render time.) Render speed is not very much affected with total size of data, but with data displayed. For user experience I recommend not to allow page longer then 100 rows with 20 columns table.

Gridact component is result of my experience working with Microsoft Excel as an user and jQuery DataTables as developer. Datatables taught me to love data in JavaScript and that's a big thanks to Allan Jardine. This motivated me to create Gridact.

This is my first public React Component, I'll be really glad for any feedback and I'll do my best to satisfy any of your requests. Thanks.

##Contact Email me at filip (a) debef . com Send me a Messenger message

Installation

Nothing but easy. npm i gridact

These modules must be installed in parent component. ~~Bootstrap must be imported in whichever parent component~~. (Bootstrap removed in version 0.6.0)

For proper function of error messages, append <div id="modalEl"></div> to your body of index.html.

Basic configuration

The basic configuration is pretty simple. Just import Gridact module and pass data and some configuration:

import Gridact from 'gridact'
import React from 'react';

const App = () => {
  const [data, setData] = useState();  
  useEffect(() => {
    yourApi().then(yourData => {
    setData(yourData)}
  )}, [])

  <Gridact    
    data={data}    
    colDefs={tableColsDef}
    wrapperDivClass={['table-responsive', 'col-xl-12']}
    tableClasses={['table', 'table-sm', 'table-striped', 'text-nowrap', 'table-bordered']}
    pagingOptions={[5, 10, 20, 50, 100]} 
    fnRowClass={(row) => {
      if (row.name_original) {
        if (row.name_original.includes('X')) return 'font-weight-bold text-danger';
        return undefined;
      }
      return undefined;
    }
    }
    serverSideEdit={editData => YourApi('yourUri', editData)
    }
    showFilter
    addRemove
    pageSelector
    pagingSelector
    searchPlaceHolder="Search..."
    onEnterMoveDown={false}
  />
      

Gridact props

data

Type: Array of Objects <mandatory>

[{col1: val, col2: val,...}, {col1: val, col2: val,...},...] 

wrapperDivClass

Type: Array, String <option> Props is joined to final classNames classNames=wrapperDivClass.join(' ') Final table is wrapped in div - main reason was enabling responsiveness in bootstraps, what requires table's outer div. For table responsiveness, use at least 'table-responsive col'

tableClasses

Type: Array | String <option> Props is joined to final classNames classNames=wrapperDivClass.join(' ') Best use with boostrap's table classes. E.g. ['table', 'table-sm', 'table-striped', 'text-nowrap', 'table-bordered']

mainTableContainerClass

Type: String Main container class, in this container is wrapped table and all controll items. (Paging, search,...)

###tableCellClass ### Type: String <option> Easy cell styling, changes style of th and td cells in table.

###setFilteredData ### Type: Function <option> Function will be passed with filtered dataset Array - subset of originaly provided table data. Necessary e.g. for sum of filtered columns.

pagingOptions

Type: Array <option> Page length options. Will always be sorted numerically, first value will be initials. Example: [20,10,50,100] - paging options will be [10,20,50,100] - initial set will be [20]. If undefined, default paging is [10, 20, 50].

fnRowClass

Type: String | Array | function <option> String or Array of classNames If function is provided, it is passed row data. Must return String or Array. Used e.g. for coloring whole row based on row data.

fnRowClass

Type: String | Array | function <option> String or Array of classNames If function is provided, it is passed row data. Must return String or Array. Used e.g. for coloring whole row based on row data.

fnCellClass

Type: String | Array | function <option> String or Array of classNames If function is provided, it is passed row data. Must return String or Array. Used e.g. for coloring cells based on row data.

initSort

Type: Object <option> Initial sort of table in object {col: colName, dir: 'asc' | 'desc' }

serverSideEdit

AcceptedValues: function <mandatory> if editable columns Function is provided with Object according to selected operation.

Objects passed to function are based on operation

edit Cell edit Passed argument: {operation: 'edit', newValue: {[editedColumn]: [newValue]}, row: [rowData]}} Required response: Promise resolved with {data: [updatedRow]} If you want to validate data server-side, you can response with {error: errorMsg}, where errorMsg is string, which will be displayed in small overlay next to edited cell. If error is in response, data will not be updated in table, previous value will be restored.

new Add new row Passed argument: {operation: 'new'} Required response: Promise resolved with {data: [newRow]} In newRow, primary_key must not be null.

delete Delete row, where is focused cell. Passed argument: {operation: 'delete', row: [rowData]} Required response: {data: 1} If value of data key is < 1, row will not be deleted in table.

click You can choose for clicking on cell value and change it on click. Passed argument: {operation: 'edit', newValue: {[editedColumn]: [oldValue]}, row: [rowData]}} You decide, how the value should change on click. Response should be {data: [updatedRow]}

showFilter, addRemove, pageSelector, pagingSelector

Type: Boolean <option> Shows/hide filter (search field), add remove row buttons, page selector (what page is displayed), paging selector (page length)

searchPlaceHolder

Type: String <option> Default: "Search..."

onEnterMoveDown

Type: Boolean If true, on enter cursor moves down. otherwise moves right.

colDefs

Columns definitions Type: Object <mandatory>

colDefs is object, where keys are column codes, values are column definitions itsels in Object.

{line_id: {
    cellRender: v => v,
    name: 'ID',
    editable: false,
    // filterEditValue: function | regexp of chars to filter out (newValue.prototype.replace(regexp, '')
    // function must return Boolean
    filterEditValue: (newValue, curCellValue, row) => (newValue.replace(/[{]|[}]|[<]|[>]|[\\]|[/]/g, '')),
    // filterEditValue: function which returns true to allow or false for disable char
    // regexp of chars allowed (newValue.prototype.match(regexp))
    filterEditChar: (char, cellValue, row) => char.match(/[a-zA-ZščřžýáíéóúůďťňĎŇŤŠČŘŽÝÁÍÉÚŮ0-9 ]/g),
    sortable: true,
    filterable: true,
    resizable: true,
    width: 80,
    hidden: false
    }
  },
...}

Column definition properties

cellRender

Type: function | string <option> If undefined, the cell is rendered with value provided in data. If string is provided, the string is returned. Function is passed cell_value and row_data. This means, you can render the cell based on other values in row. Example: cellRender: (cellValue, rowData) => if (rowData.volume) > 10 return 'TOO HIGH' else return cellValue

Special attention on circular objects as cellRender: You can pass function returning React Components to cellRender (e.g. input select in table head). As GridAct uses on row level custom property change evalution (React.memo, or formerly known as ComponentShouldUpdate), if you pass in cellRender circular objects other then React Component , application with crash. For common use this should not limit you.

tableHead (!changed in version 0.6.0 - previously "name")

Type: string <mandatory> Name of column in table header

width

Type: integer <option> Set width of current column. Default <td> css style is overflow: hidden.

editable

Type: Boolean | Function(cellValue, rowData) <option> Column cells will be editable. If value is not Boolean or Function, it is evaluated as Boolean(providedValue)

sortable

Type: Boolean <option> Column cells will be sortable. If

hidden

Type: Boolean <option> Column will be hidden. Usefull when you want to calculate cell value from multiple columns or style cell based on data from other columns but the other columns you do not want to show.

title

Type: Boolean | Function(cellValue, rowData) <option> Title (small hint over cell), e.g. when not whole content is visible, or when you want to comment the cell content. Default is false, when set to True, the content of cell is used.

cellClass

Type: String | Array | function <option> Class used for every cell in this column. String or Array of classNames If function is provided, it is passed (cellValue, rowData). Must return String or Array. Used e.g. for coloring whole column based on data of given cell or other cells in row.

thClass

Type: String | Array | function <option> Class used for every cell in this column. String or Array of classNames If function is provided, it is passed (cellValue, rowData). Must return String or Array. Used e.g. for coloring whole column based on data of given cell or other cells in row.

As the inline edit is build upon contentEditable, I paid a lot of attention to sanitize input text to avoid XSS. There two filter options for values users can write to cell.

filterEditChar

Type: RegExp | function <optional> This option is applied directly onKeyPress event - it does not let user write the characters you specify. If RegExp is provided, it is passed to character_typed.match(). Function is passed three arguments: (character_typed, cell_value_before_edit, row_data) Must return true or false. True = character is allowed, false = disallowed. Default value is (char, CellValue, rowData) => return char.match(/[a-zA-ZščřžýáíéóúůďťňĎŇŤŠČŘŽÝÁÍÉÚŮ0-9 ]/); Allowed are only alphanumeric characters included Czech ones.

filterEditValue

Type: RegExp | function <optional> Because above mentioned option does not block pasting from clipboard, and I didn't want to forbid it generally, we have to check the final value user sends to your serverSideEdit function and which will be displayed in table. As this is potential XSS risc, pay close attention to this function. Function is passed three arguments: (new_cell_value, cell_value_before_edit, row_data) Must return sanitized string. Default value is (newValue, cellValue, row) => (newValue.replace(/[{]|[}]|[<]|[>]|[\\]|[/]/g, '')) If RegExp is provided, it is passed to newValue.replace(RegExp, '')

Styling

You can fully style with own classes. See custom styles.css. GridAct is built on CSS grid.

Further development

I'll be glad if you leave me a message. What you miss, what you want, what you like. What can be added in the future:

  • customizable icons

  • custom placement of Search, add / remove buttons and paging options.

  • better page selector