From f70f2e8f92cf9b6e315d24a2f24e8dcb5b6b77e9 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Mon, 26 Nov 2018 21:28:57 +0100 Subject: [PATCH] Allow override of Datagrid Body and Row elements --- docs/List.md | 51 +++++++++++++++++ .../ra-ui-materialui/src/list/Datagrid.js | 48 ++++++++-------- .../ra-ui-materialui/src/list/DatagridBody.js | 55 ++++++++++--------- 3 files changed, 102 insertions(+), 52 deletions(-) diff --git a/docs/List.md b/docs/List.md index f3e6b721da0..495e79db92f 100644 --- a/docs/List.md +++ b/docs/List.md @@ -694,6 +694,7 @@ The datagrid component renders a list of records as a table. It is usually used Here are all the props accepted by the component: +* [`body`](#body-element) * [`rowStyle`](#row-style-function) * [`rowClick`](#rowclick) @@ -718,6 +719,56 @@ export const PostList = (props) => ( The datagrid is an *iterator* component: it receives an array of ids, and a data store, and is supposed to iterate over the ids to display each record. Another example of iterator component is [``](#the-singlefieldlist-component). +### Body element + +By default, `` renders its body using ``, an internal react-admin component. You can pass a custom component as the `row` prop to override that default. And by the way, `` has a `row` property set to `` by default for the same purpose. `` receives the row `record`, the `resource`, and a copy of the datagrid children. That means you can create a custom datagrid logic without copying several components from the react-admin source. + +For instance, to show the selection checkbox only for records that have a `selectable` field set to true, you can override `` and `` as follows: + +```jsx +// in src/PostList.js +import { Datagrid, DatagridBody, List, TextField } from 'react-admin'; +import TableCell from '@material-ui/core/TableCell'; +import TableRow from '@material-ui/core/TableRow'; +import Checkbox from '@material-ui/core/Checkbox'; + +const MyDatagridRow = ({ record, resource, id, onToggleItem, children, selected, basePath }) => ( + + {/* first column: selection checkbox */} + + {record.selectable && onToggleItem(id)} + />} + + {/* data columns based on children */} + {React.Children.map(children, field => ( + + {React.cloneElement(field, { + record, + basePath, + resource, + })} + + ))} + +) + +const MyDatagridBody = props => } />; +const MyDatagrid = props => } />; + +const PostList = props => ( + + + + ... + + +) + +export default PostList; +``` + ### Row Style Function You can customize the datagrid row style (applied to the `` element) based on the record, thanks to the `rowStyle` prop, which expects a function. diff --git a/packages/ra-ui-materialui/src/list/Datagrid.js b/packages/ra-ui-materialui/src/list/Datagrid.js index daf29bc7308..9e0e18653f1 100644 --- a/packages/ra-ui-materialui/src/list/Datagrid.js +++ b/packages/ra-ui-materialui/src/list/Datagrid.js @@ -43,12 +43,7 @@ const styles = { * It is usually used as a child of the and components. * * Props: - * - styles * - rowStyle - * - options (passed as props to ) - * - headerOptions (passed as props to mui ) - * - bodyOptions (passed as props to mui ) - * - rowOptions (passed as props to mui ) * * @example Display all posts as a datagrid * const postRowStyle = (record, index) => ({ @@ -100,22 +95,23 @@ class Datagrid extends Component { render() { const { basePath, - data, + body, children, classes, className, currentSort, + data, hasBulkActions, hover, ids, isLoading, + onSelect, + onToggleItem, resource, + rowClick, rowStyle, selectedIds, setSort, - onSelect, - onToggleItem, - rowClick, total, version, ...rest @@ -168,23 +164,21 @@ class Datagrid extends Component { )} - - {children} - + {React.cloneElement(body, { + basePath, + classes, + rowClick, + data, + hasBulkActions, + hover, + ids, + isLoading, + onToggleItem, + resource, + rowStyle, + selectedIds, + version + }, children)}
); } @@ -192,6 +186,7 @@ class Datagrid extends Component { Datagrid.propTypes = { basePath: PropTypes.string, + body: PropTypes.element.isRequired, children: PropTypes.node.isRequired, classes: PropTypes.object, className: PropTypes.string, @@ -220,6 +215,7 @@ Datagrid.defaultProps = { hasBulkActions: false, ids: [], selectedIds: [], + body: }; export default withStyles(styles)(Datagrid); diff --git a/packages/ra-ui-materialui/src/list/DatagridBody.js b/packages/ra-ui-materialui/src/list/DatagridBody.js index a0aaddbb736..8ed9b3ac9bc 100644 --- a/packages/ra-ui-materialui/src/list/DatagridBody.js +++ b/packages/ra-ui-materialui/src/list/DatagridBody.js @@ -18,6 +18,7 @@ const DatagridBody = ({ isLoading, onToggleItem, resource, + row, rowClick, rowStyle, selectedIds, @@ -25,32 +26,32 @@ const DatagridBody = ({ version, ...rest }) => ( - - {ids.map((id, rowIndex) => ( - - {children} - - ))} - -); + + {ids.map((id, rowIndex) => React.cloneElement( + row, + { + basePath, + classes, + className: classnames(classes.row, { + [classes.rowEven]: rowIndex % 2 === 0, + [classes.rowOdd]: rowIndex % 2 !== 0, + [classes.clickableRow]: rowClick, + }), + hasBulkActions, + hover, + id, + key: id, + onToggleItem, + record: data[id], + resource, + rowClick, + selected: selectedIds.includes(id), + style: rowStyle ? rowStyle(data[id], rowIndex) : null + }, + children + ))} + + ); DatagridBody.propTypes = { basePath: PropTypes.string, @@ -64,6 +65,7 @@ DatagridBody.propTypes = { isLoading: PropTypes.bool, onToggleItem: PropTypes.func, resource: PropTypes.string, + row: PropTypes.element.isRequired, rowClick: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), rowStyle: PropTypes.func, selectedIds: PropTypes.arrayOf(PropTypes.any).isRequired, @@ -75,6 +77,7 @@ DatagridBody.defaultProps = { data: {}, hasBulkActions: false, ids: [], + row: }; const areArraysEqual = (arr1, arr2) =>