React Searchtabular Using Prop loaded Rows

by John H
4 minutes


Oh my goodness - this took way longer than I'd like to admit.  The Searchtabular NPM module creates a Table Component in React that can be searched.  Seems simple enough.  They even have a pretty detailed example.  The problem I had is in the example the searchable table rows are being populated through the state object.  I wanted the component to receive my row data through a prop - passed from a parent.  This seemed pretty straight forward, but it did give me some headache.

Example Provided

import React from 'react';
import { compose } from 'redux';
import * as Table from 'reactabular-table';
import * as resolve from 'table-resolver';
import * as search from 'searchtabular';

class HighlightTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      searchColumn: 'all',
      query: {},
      columns: [
        {
          header: {
            label: 'Name'
          },
          children: [
            {
              property: 'name.first',
              header: {
                label: 'First Name'
              },
              cell: {
                formatters: [search.highlightCell]
              }
            },
            {
              property: 'name.last',
              header: {
                label: 'Last Name'
              },
              cell: {
                formatters: [search.highlightCell]
              }
            }
          ]
        },
        {
          property: 'age',
          header: {
            label: 'Age'
          },
          cell: {
            formatters: [search.highlightCell]
          }
        }
      ],
      rows: [
        {
          id: 100,
          name: {
            first: 'Adam',
            last: 'West'
          },
          age: 10
        },
        {
          id: 101,
          name: {
            first: 'Brian',
            last: 'Eno'
          },
          age: 43
        },
        {
          id: 103,
          name: {
            first: 'Jake',
            last: 'Dalton'
          },
          age: 33
        },
        {
          id: 104,
          name: {
            first: 'Jill',
            last: 'Jackson'
          },
          age: 63
        }
      ]
    };
  }
  render() {
    const { searchColumn, columns, rows, query } = this.state;
    const resolvedColumns = resolve.columnChildren({ columns });
    const resolvedRows = resolve.resolve({
      columns: resolvedColumns,
      method: resolve.nested
    })(rows);
    const searchedRows = compose(
      search.highlighter({
        columns: resolvedColumns,
        matches: search.matches,
        query
      }),
      search.multipleColumns({
        columns: resolvedColumns,
        query
      }),
    )(resolvedRows);

    return (
<div>
        <div className="search-container">
          <span>Search</span>
          <search.Field
            column={searchColumn}
            query={query}
            columns={resolvedColumns}
            rows={resolvedRows}
            onColumnChange={searchColumn => this.setState({ searchColumn })}
            onChange={query => this.setState({ query })}
          />
        </div>
        <Table.Provider columns={resolvedColumns} className="Table">
        <Table.Header  headerRows={resolve.headerRows({ columns })}
          />
          <Table.Body rows={searchedRows} rowKey="id" />        
        </Table.Provider>
      </div>
    );
  }
}

export default HighlightTable;

Solution

This problem with loading the content through the state is that it can't really be changed, and I wanted to fetch it and load it through the props. So to fix this you have to remove the rows property from the state, remove the const value in the render method that assigns its value from the state and instead assign it to the prop value.

/*
import React from 'react';
import { compose } from 'redux';
import * as Table from 'reactabular-table';
import * as resolve from 'table-resolver';
import * as search from 'searchtabular';
*/

class HighlightTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      searchColumn: 'all',
      query: {},
      columns: [
        {
          header: {
            label: 'Name'
          },
          children: [
            {
              property: 'name.first',
              header: {
                label: 'First Name'
              },
              cell: {
                formatters: [search.highlightCell]
              }
            },
            {
              property: 'name.last',
              header: {
                label: 'Last Name'
              },
              cell: {
                formatters: [search.highlightCell]
              }
            }
          ]
        },
        {
          property: 'age',
          header: {
            label: 'Age'
          },
          cell: {
            formatters: [search.highlightCell]
          }
        }
      ]
    };
  }
  render() {
    const { searchColumn, columns, query } = this.state;

    ///// THIS IS WHERE THE ROWS ARE LOADED THROUGH THE PROPS
    const rows = this.props.rows;

    const resolvedColumns = resolve.columnChildren({ columns });
    const resolvedRows = resolve.resolve({
      columns: resolvedColumns,
      method: resolve.nested
    })(rows);
    const searchedRows = compose(
      search.highlighter({
        columns: resolvedColumns,
        matches: search.matches,
        query
      }),
      search.multipleColumns({
        columns: resolvedColumns,
        query
      }),
    )(resolvedRows);

    return (
      <div>
        <div className="search-container">
          <span>Search
          <search.Field
            column={searchColumn}
            query={query}
            columns={resolvedColumns}
            rows={resolvedRows}
            onColumnChange={searchColumn => this.setState({ searchColumn })}
            onChange={query => this.setState({ query })}
          />
        </div>
        <Table.Provider columns={resolvedColumns}>
          <Table.Header
            headerRows={resolve.headerRows({ columns })}
          />

          <Table.Body rows={searchedRows} rowKey="id" />
        </Table.Provider>
      </div>
    );
  }
}

export default HighlightTable;

Related Articles

Javascript searching through a string

[caption id="attachment_612" align="aligncenter" width="1000"] Searching a string in...

John H John H
4 minutes

Hashtag Searching on Popular Social Networks

http://stackoverflow.com/questions/19034754/facebook-api-search-for-hashtag...

John H John H
~1 minute

Less Pros and Cons

You might be wondering what Less is?  It is a Css preprocessor - just like Sass or Stylus.  So,...

John H John H
8 minutes