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 specifyfalse
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.