Customization

Please Note: Styling is similar to customization but is in its own section for clarity.

Griddle comes with a number of customization options to help it fit with your project goals.


Default Columns

Use the columns property to set the default columns in a Griddle grid. Please see the quickstart guide for an example.

columns
array (of string) - The columns that should be displayed by default. The other columns can be chosen via the grid settings. If no columns are set, Griddle will display all columns by default.

Column Metadata

The column meta data property is used to specify column properties that are not part of the result data object. For instance, if you want to specify a displayName that is different than the property name in the result data, the columnMetadata property is where this would be defined.

Griddle parses and evaluates the following columnMetadata object properties:

columnName
string (required) - this is the name of the column as it appears in the results passed into Griddle.
sortable
bool - Determines whether or not the user can sort this column (defaults to true, so specify false to disable sort)
customCompareFn
function
with 1 argument specifies a function that defines the sort order of the column data. Passed to _.sortBy method, invoked with 1 argument.
with 2 arguments specifies a function that defines the sort order of the column data. Passed to standard JS sort method, invoked ith 2 arguments. Useful, for example, wih naturalSort(a, b) from javascript-natural-sort
multiSort
object - allows to specify multiple sorting when sorting current column. Specified columns will be sorted after current
multiSort: { columns: ['name'], orders: ['asc'] }
order
int - The order that this column should appear in Griddle.
locked
bool - Determines whether or not the user can disable this column from the settings.
cssClassName
string - The css class name to apply to this column.
titleStyles
object - collection of styles applied to column header
displayName
string - The display name for the column. This is used when the name in the column heading and settings should be different from the data passed in to the Griddle component.
customComponent
React Component - The component that should be rendered instead of the standard column data. This component will still be rendered inside of a TD element. (more information below in the Custom Columns section.)
customHeaderComponent
React Component - The component that should be rendered instead of the standard header data. This component will still be rendered inside of a TH element. (more information below in the Custom Columns section.)
customHeaderComponentProps
object - An object containing additional properties that will be passed into the custom header component. (more information below in the Custom Columns section.)

However, you are also able to pass other properties in as columnMetadata.

columnMetadata can be accessed on the metadata property of a Custom Column component.

Example:

Assume we want to reverse the columns so name would be last, followed by followed by city, state, company, country and favorite number. Also we want the name column heading to read Employee Name instead of name.

Our metadata object would look something like

  {
    "columnName": "name",
    "order": 9,
    "locked": false,
    "visible": true,
    "displayName": "Employee Name"
  },
  {
    "columnName": "city",
    "order": 8,
    "locked": false,
    "visible": true
  },
  {
    "columnName": "state",
    "order": 7,
    "locked": false,
    "visible": true
  },
  {
    "columnName": "country",
    "order": 6,
    "locked": false,
    "visible": true
  },
  {
    "columnName": "company",
    "order": 5,
    "locked": false,
    "visible": true
  },
  {
    "columnName": "favoriteNumber",
    "order":  4,
    "locked": false,
    "visible": true,
    "displayName": "Favorite Number",
    "sortable": false
  }

We would then load Griddle as follows:

React.render(
  <Griddle results={fakeData} columnMetadata={exampleMetadata} showFilter={true}
    showSettings={true} columns={["name", "city", "state", "country"]}/>,
    document.getElementById('griddle-metadata')

Custom Columns

Custom column components are defined in the Column Metadata object. The components are passed data, rowData, metadata properties.

data
object - the data that would normally be rendered in the column.
rowData
object - the data for all items in the same row
metadata
object - The columnMetadata object
Example:

We are going to make the body of one of the columns a link. This link will use data from another column to determine the href.

Assume we have the following data for our grid:

var someData =  [
{
  "id": 0,
  "name": "Mayer Leonard",
  "city": "Kapowsin",
  "state": "Hawaii",
  "country": "United Kingdom",
  "company": "Ovolo",
  "favoriteNumber": 7
  },
  {
    "id": 1,
    "name": "Koch Becker",
    "city": "Johnsonburg",
    "state": "New Jersey",
    "country": "Madagascar",
    "company": "Eventage",
    "favoriteNumber": 2
  },
  ...
];

We want the name column to be a link to /speakers/state/name (where state and name are pulled in from the data). We can define a customComponent to be rendered as follows:

var LinkComponent = React.createClass({
  render: function(){
    url ="speakers/" + this.props.rowData.state + "/" + this.props.data;
    return <a href={url}>{this.props.data}</a>
  }
});

Additionally, we want the city and state column headers to be highlighted a specific color and have a filter by column input. We can define a custom header component as:

var HeaderComponent = React.createClass({
  textOnClick: function(e) {
    e.stopPropagation();
  },

  filterText: function(e) {
    this.props.filterByColumn(e.target.value, this.props.columnName)
  },

  render: function(){
    return (
      <span>
        <div><strong style={{color: this.props.color}}>{this.props.displayName}</strong></div>
        <input type='text' onChange={this.filterText} onClick={this.textOnClick} />
      </span>
    );
  }
});

Please note: filterByColumn is a method that is passed as a prop to any customHeaderComponent.

From there, we will set the customComponent value in the name columnMetadata object to this LinkComponent. We're also going to update state and city's customHeaderComponent and customHeaderComponentProps.

var columnMeta = [
  {
  ...
  "columnName": "name",
  "order": 1,
  "locked": false,
  "visible": true,
  "customComponent": LinkComponent
  },
  {
  ...
  "columnName": "city",
  "customHeaderComponent": HeaderComponent,
  "customHeaderComponentProps": { color: 'red' }
  },
  {
  ...
  "columnName": "state",
  "customHeaderComponent": HeaderComponent,
  "customHeaderComponentProps": { color: 'blue' }
  },
  ...
];

Now, when Griddle is rendered with this columnMetadata, it should write the link as expected.

React.render(<Griddle data={someData} columnMetadata={columnMeta} />,
   document.getElementById('something'));

Custom sorting

Example:

In this example we are going to sort Employee Name column by last name, followed by first name:

var exampleMetadata = [
  {
  "columnName": "id",
  "order": 1,
  "locked": false,
  "visible": false,
  "displayName": "ID"
  },
  {
  "columnName": "name",
  "order": 9,
  "locked": false,
  "visible": true,
  "displayName": "Employee Name",
  "compare": function(name) {
      var a = name.split(" ");
      return a[1] + " " + a[0];
    }
  },
  ...
]

Then, like in first example, but specify initialSort column:

React.render(
  <Griddle results={fakeData} columnMetadata={exampleMetadata} showFilter={true}
    showSettings={true} columns={["name", "city", "state", "country"]} initialSort="name"/>,
    document.getElementById('griddle-metadata')

Row Metadata

bodyCssClassName
function or string - If you supply a string, that class is applied to all rows. If you supply a function, the rows data is supplied to that function as the first argument and you are expected to return the css class name. This is useful if you want to style a row based on the rows data.
Example:
var rowMetadata = {
    "bodyCssClassName": function(rowData) {
        if (rowData.action === "added") {
            return "green-row";
        } else if (rowData.action === "removed") {
            return "red-row";
        } else if (rowData.action === "transfer") {
            return "blue-row";
        }
        return "default-row";
    }
};

return (
    <div className="griddle-container">
        <Griddle results={this.state.rows} rowMetadata={rowMetadata} />
    </div>
)

Custom Row Format

Sometimes you may want to display grid data in a format other than a grid but still have pagination, filtering, etc. This type of formatting can be accomplished with the custom row format properties. To use custom row formatting, the useCustomRowComponent and the customRowComponent properties will need to be set.

useCustomRowComponent
bool - determines if custom row formats are applied
customRowComponent
Component - the component to render in place of a grid row. This component receives a property named data
customRowComponentClassName
string - the CSS class name to apply to the format component.
enableToggleCustom
bool - whether or not the user should be able to toggle between custom format and grid format.
Example:

We are going to render our grid as a series of cards, keeping the pagination and filtering from Griddle in tact. Assume we are using the same data in the custom column example. We will need to create a custom component as follows:

var OtherComponent = React.createClass({
  getDefaultProps: function(){
    return { "data": {} };
  },
  render: function(){
    return (<div className="custom-row-card">
    <div className="name"><strong>{this.props.data.name}</strong><small>{this.props.data.company}</small></div>
    <div>{this.props.data.city}</div>
    <div>{this.props.data.state}, {this.props.data.country}</div>
    </div>);
  }
});

From there, Griddle can be rendered with the useCustomRowComponent and customRowComponent properties:


Custom Grid Format

In some cases, it may be ideal to use Griddle but display a global format other than a grid or series of rows. Assume we have an object containing temperature data for years and we want to display this data with a trend line chart. This is possible with a custom grid format component. To use custom grid formatting the useCustomGridComponent and customGridComponent properties need to be set.

useCustomGridComponent
bool - determines if custom row formats are applied
customGridComponent
Component - the component to render in place of a grid row. This component receives a property named data
customGridComponentClassName
string - the CSS class name to apply to the format component.
enableToggleCustom
bool - whether or not the user should be able to toggle between custom format and grid format.
Example:

As stated above we are going to render a visualization of temperature data rather than a chart. To start off we need to create a visualization component that uses a data property to obtain its values (the following example uses the awesome chartist library and accompanying react component):

var TestLineChart = React.createClass({
  render: function(){
    var simpleLineChartData = {
      labels: _.keys(this.props.data[0]),
      series: []
    };

    _.each(this.props.data, function(item){
      simpleLineChartData.series.push(_.values(item));
      });
      return <ChartistGraph data={simpleLineChartData} type={'Line'} />
  }
});

Custom Filtering and Filter Component

Griddle supports custom filtering and custom filter components. In order to use a custom filter function set the property useCustomFilterer to true and pass in a function to the customFilterer property. To use a custom filter component set useCustomFilterComponent to true and pass a component to customFilterComponent.

Example:

This example shows how to make a custom filter component with a custom filter function that does a case-insensitive search through the items. The component must call this.props.changeFilter(val) when the filter should be updated. In the example below we pass a string but any variable type can be used as long as the filter function is expecting it, for example an advanced query could be passed in using an object. The filter function signature takes the items to be filtered and the query to filter them by.

      squish = require('object-squish');

  var customFilterFunction = function(items, query) {
    return _.filter(items, (item) => {
      var flat = squish(item);

      for (var key in flat) {
        if (String(flat[key]).toLowerCase().indexOf(query.toLowerCase()) >= 0) return true;
      };
      return false;
    });
  };

  var customFilterComponent = React.createClass({
    getDefaultProps: function() {
      return {
        "query": ""
      }
    },

    searchChange: function(event) {
      this.props.query = event.target.value;
      this.props.changeFilter(this.props.query);
    },

    render: function() {
      return (
        <div className="filter-container">
          <input type="text"
                 name="search"
                 placeholder="Search..."
                 onChange={this.searchChange} />
        </div>
      )
    }
  });

Then initialize Griddle:

React.render(
  <Griddle results={fakeData} showFilter={true}
  useCustomFilterer={true} customFilterer={customFilterFunction}
  useCustomFilterComponent={true} customFilterComponent={customFilterComponent}/>,
  document.getElementById('griddle-metadata')

Custom Paging Component

If you want to customize the paging component, just set the property 'useCustomPagerComponent' to true and pass in another component as property named 'customPagerComponent'. The example component below shows 11 buttons (5 previous, current, 5 next):

useCustomPagerComponent
bool - Use custom pagination component rather than default pager. default: false
customPagerComponent
object - The custom pagination component. default: {}
customPagerComponentOptions
object - Any options to be passed to the custom pagination component. default: {}
Example
var OtherPager = React.createClass({
    getDefaultProps: function(){
        return{
            "maxPage": 0,
            "nextText": "",
            "previousText": "",
            "currentPage": 0,
        }
    },
    pageChange: function(event){
        this.props.setPage(parseInt(event.target.getAttribute("data-value")));
    },
    render: function(){
        var previous = "";
        var next = "";

        if(this.props.currentPage > 0){
            previous = <span onClick={this.props.previous} className="previous"><i className="glyphicon glyphicon-arrow-left"></i>{this.props.previousText}</span>
        }

        if(this.props.currentPage != (this.props.maxPage -1)){
            next = <span onClick={this.props.next} className="next">{this.props.nextText}<i className="glyphicon glyphicon-arrow-right"></i></span>
        }

        var options = [];

      var startIndex = Math.max(this.props.currentPage - 5, 0);
      var endIndex = Math.min(startIndex + 11, this.props.maxPage);

      if (this.props.maxPage >= 11 && (endIndex - startIndex) <= 10) {
        startIndex = endIndex - 11;
      }

        for(var i = startIndex; i < endIndex ; i++){
          var selected = this.props.currentPage == i ? "current-page-selected" : "";
            options.push(<button className={selected} data-value={i} onClick={this.pageChange}>{i + 1}</button>);
        }

        return (
            <div className="row custom-pager">
                <div className="col-xs-4">{previous}</div>
                <div className="col-xs-4 center pages">
                    {options}
                </div>
                <div className="col-xs-4 right">{next}</div>
            </div>
        )
    }
});

Then initialize your component as follows:

<Griddle results={fakeData} tableClassName="table" useCustomRowComponent="true"
  customRowComponent={OtherComponent} useCustomPagerComponent="true" customPagerComponent={OtherPager} />

No Data

Griddle will, by default, show a message if there is no data in the result set. There are two ways that it can be customized though.

Basic NoData message

The first way to customize what Griddle does when there is no data is setting the noDataMessage property.

noDataMessage
string - The message that will be displayed when there is no data
noDataClassName
string - The CSS class name to apply to the grid when no data is available Default: griddle-nodata
Example:
<Griddle noDataMessage={"No data could be found."} />

NoData Component

Outside of the NoData message, Griddle can take a customNoDataComponent that will be displayed when there are no records.

customNoDataComponent
object - The component that will be displayed when there is no data
Example:
var NoDataComponent = React.createClass({
    render: function(){
      return (<div>
          <h1>No data is available</h1>
          <a href="http://www.google.com">You can google for more data</a>
        </div>
      );
    }
});

React.render(<Griddle customNoDataComponent={NoDataComponent} />, document.getElementById("some-id"));

Custom Icons

Please see the styling section for custom icons.

Griddle is a project maintained by Ryan Lanciaux and Joel Lanciaux in collaboration with all of the awesome contributors!

© 2015 Ryan Lanciaux | DynamicTyped
Example data has been generated with json-generator.com. Any data that resembles real people, places, companies, etc. is coincidence.