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

@trungdq88/react-datatable

v1.0.1

Published

DataTable component build with ReactJS, supports sort, search, filter, paging, custom cell value and more!

Downloads

5

Readme

react-datatable

DataTable component build with ReactJS, supports sort, search, filter, paging, custom cell value and more!

DEMO: http://trungdq88.github.io/react-datatable

How it looks like

Install

npm install --save @trungdq88/react-datatable

Usage

Be patience, it takes few steps to get make a minimum example but it totally worth!

1. Define a data source

Say I want to create a Restaurant list to DataTable, I first create a DataSource class which tells the DataTable where do I get the data from.

    import { DataSource } from '@trungdq88/react-datatable';
    
    // Don't forget to extends from DataSource
    export default class RestaurantDataSource extends DataSource {

      // This class will be initiate with a unique name and data
      constructor(name, data) {
        super(name);
        this.meta = {
          keyField: 'id',
          searchFields: ['name'],
          listFields: [
            ['Name', 'name'],
            ['Price', 'price'],
          ],
        };

        // Assign data to `items` property
        this.items = data;
      }

      fetch() {
        // For minimum example, we display all items in only 1 page (no pagination)
        this.data = {
          page: 1,
          total: this.items.length,
          entities: this.items,
          perpage: this.items.length,
        };

        // Emit event
        this.trigger('change');
      }
    }

2. Create a data source object

Create a data source object from RestaurantDataSource class with data

    this.restaurantDataSource = new RestaurantDataSource('restaurants', [
        {name: 'Japanese food'},
        {name: 'Vietnamese food'},
        {name: 'Thai food'},
    ]);

3. Create DataTable component:

In your render() method:

    <DataTable id="restaurants-table"
               dataSource={this.restaurantDataSource} />

Your data table should be displayed right now.

Customize the table

DataSource is the heart of DataTable. It can be customized a lot to serve various data types.

The this.meta property

Each DataSource class has a property named meta to describes the data, it tells the DataTable how to display data correctly.

Say, my data is an array of same schema objects:

    [
        {
            id: 'VX129',
            name: 'Vietnamese food',
            price: '$$$$ (<100$)',
            img: 'http://abc.com/some_image.png',
        },
        {
            id: 'VX212',
            name: 'Thai food',
            price: '$$$ (<60$)',
            img: 'http://abc.com/some_image.png',
        }
    ]

This is the meta object for that data:

        this.meta = {
          keyField: 'id',
          searchFields: ['name'],
          listFields: [
            // Format: [{Heading text}, {Property name}]
            ['Name', 'name'],
            ['Price', 'price'],
          ],
        };

DataTable display:

    # | Name                | Price
    1 | Vietnamese food     | $$$$ (<100$)
    2 | Food food           | $$$ (<60$)

Notice: the data must be an array, and all the objects in that array must share the same schema.

listFields property and transform object

From above example, you might know that the listFields property describes how the data will be display on DataTable (which property name displays in which column Header).

In some cases, we need more advanced method to customize the data displayed (for example display an image instead of regular text. That where we use the transform object.

          listFields: [
            // Format: [{Heading text}, {Property name}]
            ['Image', {
                // Field to be transformed
                field: 'img',
                // Receive `img` property in the first param
                // Returns {string} or `ReactElement` to be displayed
                transform: function (img) {
                    return <img src={img} />;
                }
            }],
            ['Name', 'name'],
            ['Price', 'price'],
          ],

The transform function also receive the context (this variable) of the parent data object, that means you can reference to other property inside that transform object. In the example bellow, I added a link (using id property) to "Name" column:

          listFields: [
            ['Image', {
                field: 'img',
                transform: function (img) {
                    return <img src={img} />;
                }
            }],
            ['Name', {
                field: 'name',
                transform: function (name) {
                    return <a href={'http://example.com/restaurant/detail/' + this.id}>{name}</a>;
                }
            }],
          ],

The this.fetch method.

As you can see in RestaurantDataSource, the fetch method only assign data to this.data and trigger change event. In fact, the fetch methods accept various parameters. See this in the DataSource class source code.

      /**
       * Start to fetch data (via API or whatever)
       * Please implement this method to get data from any API endpoint
       * or from a static array. This method should assign the `this.data`
       * variable in the right schema which later will be get from `this.get()`
       * method.
       * 
       * Don't forget to call `this.trigger('change')` when the data is loaded
       * 
       * @page {number} requested page number
       * @search {string} keyword entered in search box
       * @sortProperty {string} property of the column that need to be sorted
       * @sortOrderDesc {boolean} equals `true` if sort in Desc order, `false` = Asc
       * @perpage {number} number of items to displayed in one page
       */
      fetch(page, search, sortProperty, sortOrderDesc, filter, perpage) {
        console.error('Not implemented!');
      }

So basically, you can create a data source that get data every where. Check this example on get data from Github issue API

      fetch(page, search, sortProperty, sortOrderDesc, filter, perpage) {
        const apiEndPoint = 'https://api.github.com/repos/facebook/react/issues';

        // Build URL
        // 1. Pagination
        let query = '&page=' + page;
        if (perpage) query += '&per_page=' + perpage;
        
        // 2. Search
        // Sad, GitHub API does not provide search
        // if (search) query += '&query=' + search; 
        
        // 3. Sort
        if (sortProperty && sortOrderDesc !== null) {
          query += '&sort=' + sortProperty +
            '&direction=' + (sortOrderDesc ? 'desc' : 'asc');
        }

        // 4. Filter // Sad, GitHub API does not provide filter
        //if (filter && Object.keys(filter).length > 0) {
        //  query += Object.keys(filter).map((property) => {
        //    return '&' + property + '=' + filter[property];
        //  });
        //}

        // Send ajax request to URL
        api.get(apiEndPoint + '?' + query)
          .done((response) => {
            // Set data
            this.data = {
              page: page,
              total: undefined, 
              entities: response,
              perpage: perpage || this.DEFAULT_PER_PAGE,
              search: search,
              sortProperty: sortProperty,
              sortOrderDesc: sortOrderDesc,
            };

            // Emit event
            this.trigger('change');
          }).fail(() => {
          this.trigger('failed');
        });

More example on how to use DataSource please see in examples/src

Search

Searchable fields is setted in meta object with searchFields {array({string})) property.

        this.meta = {
          keyField: 'id',
          // Array of property name that will be used for search
          searchFields: ['name'],
          listFields: [
            ...
          ]

In order to display a search box to the top of the table, add searchable property to <DataTable> element.

    <DataTable id="restaurants-table"
               dataSource={this.restaurantDataSource} 
               searchable />

When user click search button, the fetch method will be called with search parameter contains the keyword entered in the search box.

Sort

By default, all the property is sortable. If <DataTable> has sortable property, it will display a sort icon right next to the column header, clicking to the sort icon will trigger the fetch method with sortProperty and sortOrderDesc param.

    <DataTable id="restaurants-table"
               dataSource={this.restaurantDataSource} 
               searchable
               sortable />

If you want to disable sorting for a speficic column, add a 'no-sort' string to the 3-rd element in listFields item:

            ['Image', {
                field: 'img',
                transform: function (img) {
                    return <img src={img} />;
                },
            }, 'no-sort'],

You can use true instead of no-sort string, as long as the value is not undefined.

    if (listField[2] === undefined) {
        // Display sort icon
    } else {
        // Hide sort icon
    }

Filter

You can define the filter value for a specific column by adding a 4-th element in listFields item:

      listFields: [
        ['Image', {
            field: 'img',
            transform: function (img) {
                return <img src={img} />;
            }
        }],
        ['Name', {
            field: 'name',
            transform: function (name) {
                return <a href={'http://example.com/restaurant/detail/' + this.id}>{name}</a>;
            }
        }],
        ['Price', 'price', undefined, [
          {id: '$$ (<$30)', label: '$$ (<$30)'},
          {id: '$$$ (<$60)', label: '$$$ (<$60)'},
          {id: '$$$$ (<$100)', label: '$$$$ (<$100)'},
          {id: '$$$$$ (>$100)', label: '$$$$$ (>$100)'},
        ]]
      ]

Filter setting is an array of objects, which must follow this schema:

    {
        id: '',     // Id value of the filter
        label: '',  // Label to display in DataTable
    }

Handle filter in fetch method: fetch method will receive a filter object

    {
        propertyName1: propertyValue1,
        propertyName2: propertyValue2,
        ...
    }

See an example on filtering data in fetch method:

      fetch(page, search, sortProperty, sortOrderDesc, filter, perpage) {
        let data = this.items;
        // 1. Filter
        if (filter && Object.keys(filter).length > 0) {
          const filterFunc = function (item) {
            return item[this] === filter[this]
          };
          for (const property in filter) {
            if (property) {
              data = data.filter(filterFunc.bind(property));
            }
          }
        }
      ...

Extra columns

In some cases, you might want to add extra columns, for example add a "Edit", "Remove" button to the last column. Create a extraColumns array to describe the column you want to add and then call dataSource.setExtraColumns to add the column.

    this.restaurantDataSource = new RestaurantDataSource(
        'restaurant', fakeData.restaurants);
    
    const onOrderRestaurant = (restaurant) => {
        alert('Order placed for ' + restaurant.name);
    }
    
    const extraColumns = [
      ['Action', {
        'field': '',
        transform: function () {
          return (
            <button onClick={onOrderRestaurant.bind(self, this)}
                    className="btn btn-primary btn-sm">Order this restaurant</button>
          );
        },
      }, 'no-sort'],
    ];
    this.restaurantDataSource.setExtraColumns(extraColumns);

Basically, DataSource will concat the extraColumns with listFields and return to DataTable, therefore all the rules applied for listFields is the same with extraColumns.

Development & Build

Build the demo page:

npm install
npm run build

Start dev server for development

npm start

No tests available yet.