30 September 2016

Column Level Filter in Fixed Data Table in ReactJS or React.js

Hi All,

In this post I am going to show you how you can add the filter on top of every column to filter the result.

For this example I am going to use the existing application which we have done in following link:

http://www.code4fusion.com/2016/09/showing-data-in-tabular-format-using.html

To add the input text on the header of the table we need to add the following method in your component class in the jsx file.

renderHeader(label, cellDataKey) {
  return <div>
        <span>{label}</span>
          <div>
            <br />
            <input type="text"/>
          </div>
      </div>;
}


After adding this in your component now you need to call this method from each column by specifying the following on each column.

headerRenderer={this.renderHeader}

So at this point of time the complete code for your table should like like this:

 <Table
      filterable={['id', 'departmentId', 'departmentName']}
      noDataText="No matching records found"
      height={h}
      width={600}
      rowsCount={rows.length}
      rowHeight={30}
      headerHeight={80}
      rowGetter={function(rowIndex) {return rows[rowIndex]; }}>
      <Column dataKey="id" width={200} height={50} label="Searial Number" headerRenderer={this.renderHeader}/>
      <Column dataKey="departmentId" width={200} label="Department Id" headerRenderer={this.renderHeader}/>
      <Column dataKey="departmentName" width={200} label="Department Name" headerRenderer={this.renderHeader}/>
    </Table>


Once it will  be done now we need to write the method which will handle the filter functionality.

For this we will write one more method in the component as follows:

 onFilterChange(cellDataKey, event) {
  if (!event.target.value) {
    this.setState({
      departments: this.state.departments1,
    });
  }
  var filterBy = event.target.value.toString().toLowerCase();
  var size = this.state.departments1.length;
  var filteredList = [];
  for (var index = 0; index < size; index++) {
    var v = this.state.departments1[index][cellDataKey];
    if (v.toString().toLowerCase().indexOf(filterBy) !== -1) {
      filteredList.push(this.state.departments1[index]);
    }
  }
  this.setState({
    departments: filteredList,
  });
}


After adding this method we need to call it from the input text mentioned in the filter. so now modify the filter method as follows:

 renderHeader(label, cellDataKey) {
  return <div>
        <span>{label}</span>
          <div>
            <br />
            <input type="text" onChange={this.onFilterChange.bind(this, cellDataKey)}/>
          </div>
      </div>;
}


After adding these codes your jsx file will look like as follows:

import React from "react";
import ReactDOM from "react-dom";
import {Table, Column, Cell} from 'fixed-data-table';


var DepartmentGridTable = React.createClass({
 getInitialState: function() {
    return {departments: [],  departments1:[], rows:[]};
  },
    
 renderHeader(label, cellDataKey) {
  return <div>
        <span>{label}</span>
          <div>
            <br />
            <input type="text" onChange={this.onFilterChange.bind(this, cellDataKey)}/>
          </div>
      </div>;
},

onFilterChange(cellDataKey, event) {
  if (!event.target.value) {
    this.setState({
      departments: this.state.departments1,
    });
  }
  var filterBy = event.target.value.toString().toLowerCase();
  var size = this.state.departments1.length;
  var filteredList = [];
  for (var index = 0; index < size; index++) {
    var v = this.state.departments1[index][cellDataKey];
    if (v.toString().toLowerCase().indexOf(filterBy) !== -1) {
      filteredList.push(this.state.departments1[index]);
    }
  }
  this.setState({
    departments: filteredList,
  });
},

componentDidMount: function() {
     $.ajax({
      url: this.props.dataUrl,
      dataType: 'json',
      success: function(data) {
     
      var deptArray=[];

var arrayLength = data.length;
for (var i = 0; i < arrayLength; i++) {
deptArray.push(
{                     
                        "id" : i+1,
                        departmentId: data[i].departmentId,
                        departmentName:  data[i].departmentName
                    });

}
         this.setState({departments: deptArray});
         this.setState({departments1: deptArray});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.dataUrl, status, err.toString());
      }.bind(this)
    });
  },
 render: function(){
 var rows = this.state.departments;
 var h= rows.length*30+85;
    return <Table
      filterable={['id', 'departmentId', 'departmentName']}
      noDataText="No matching records found"
      height={h}
      width={600}
      rowsCount={rows.length}
      rowHeight={30}
      headerHeight={80}
      rowGetter={function(rowIndex) {return rows[rowIndex]; }}>
      <Column dataKey="id" width={200} height={50} label="Searial Number" headerRenderer={this.renderHeader}/>
      <Column dataKey="departmentId" width={200} label="Department Id" headerRenderer={this.renderHeader}/>
      <Column dataKey="departmentName" width={200} label="Department Name" headerRenderer={this.renderHeader}/>
    </Table>;
     }

 });

ReactDOM.render(
 <DepartmentGridTable dataUrl ="http://localhost:9001/TestRestEasy/rest/departments/"/>,
  document.querySelector("#container")
);
 

 And your .html file will look like this:

 <!DOCTYPE html>
<html>
<head>
  <script src="http://code.jquery.com/jquery-2.2.0.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/fixed-data-table/0.6.3/fixed-data-table.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/fixed-data-table/0.6.3/fixed-data-table.min.css"></script>
 <link href="https://cdnjs.cloudflare.com/ajax/libs/fixed-data-table/0.6.3/fixed-data-table.css" rel="stylesheet">
</head>
<body>
  <div id="container"></div>
  <script src="output/myCode.js"></script>
</body>
</html>


Now once you launch the application and open the .html file in the browser you can see the following:


 So in the above screenshot the data is coming from rest services and we are showing in the react fixed data table. you can see the filter also in the above screenshot.

Once you type anything in the filter you can see the corresponding result in the table as shown below:

 











Now you can see from the above screenshot the filter is working perfectly fine in the table.

Happy Coding :)

4 on: "Column Level Filter in Fixed Data Table in ReactJS or React.js"
  1. Hi friend,

    I got a error when I set headerRender property in Column "commons.chunk.js:4667 Uncaught TypeError: Cannot read property 'hasOwnProperty' of undefined"
    why¿? I am new to reactjs.
    thanks

    ReplyDelete
    Replies
    1. Hi Alfredo,

      It is veryu difficult to comment on this without looking into code. But alternatively you can check the browser console of inspect element feature for complete error and line of code where the error is happening.

      Thanks,
      Kunal

      Delete
    2. Thanks Kunal,

      The error is the file commons.chunk.js in rops.hasOwnProperty(propName):
      *
      * @param {ReactElement} element
      */
      function checkAndWarnForMutatedProps(element) {
      if (!element._store) {
      // Element was created using `new ReactElement` directly or with
      // `ReactElement.createElement`; skip mutation checking
      return;
      }

      var originalProps = element._store.originalProps;
      var props = element.props;

      for (var propName in props) {
      if (props.hasOwnProperty(propName)) {
      if (!originalProps.hasOwnProperty(propName) ||
      !is(originalProps[propName], props[propName])) {
      .........


      But in FixedDataTableColumn.react.js the property exists:
      /**
      * The cell renderer that returns React-renderable content for table column
      * header.
      * ```
      * function(
      * label: ?string,
      * cellDataKey: string,
      * columnData: any,
      * rowData: array,
      * width: number
      * ): ?$jsx
      * ```
      */
      headerRenderer: PropTypes.func,

      So I don't know why this props is wrong. I would like have it for sort rows, but else it's possible I'll find a alternative for sort by buttons u others.

      Thanks.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete