Reputation: 69
Im using react-admin 3.8.1
and Im working on customize 's table header to implement below - UDI Key
what I found is
const MyDatagridRow = ({ record, resource, id, onToggleItem, children, selected, basePath }) => (
<TableRow key={id}>
{/* first column: selection checkbox */}
<TableCell padding="none">
<Checkbox
disabled={record.selectable}
checked={selected}
onClick={() => onToggleItem(id)}
/>
</TableCell>
{/* data columns based on children */}
{React.Children.map(children, field => (
<TableCell key={`${id}-${field.props.source}`}>
{React.cloneElement(field, {
record,
basePath,
resource,
})}
</TableCell>
))}
</TableRow>
);
const MyDatagridBody = props => <DatagridBody {...props} row={<MyDatagridRow />} />;
const MyDatagrid = props => <Datagrid {...props} body={<MyDatagridBody />} />;
const PostList = props => (
<List {...props}>
<MyDatagrid>
<TextField source="title" />
...
</MyDatagrid>
</List>
)
but this way I only can customize the datagrid's body, not table header.
for now, only way for that seems changing the Datagrid.tsx but I don't want to do this.
if anyone knows the solution. please let me know thanks.
Upvotes: 0
Views: 2265
Reputation: 176
In last versions of react-admin (3.19.x) you can define your own body and other parts:
https://marmelab.com/react-admin/List.html#the-datagrid-component
See the "body" property for more information, may be helps
Upvotes: 0
Reputation: 7335
React-admin's <Datagrid>
doesn't offer a way to customize the table header. You'll have no other solution but to use your own <Datagrid>
component.
You can take the following code as a base (copied from the react-admin source, and migrated from TS to JS):
import * as React from 'react';
import {
isValidElement,
Children,
cloneElement,
useCallback,
FC,
ReactElement,
} from 'react';
import PropTypes from 'prop-types';
import {
Checkbox,
Table,
TableProps,
TableCell,
TableHead,
TableRow,
} from '@material-ui/core';
import classnames from 'classnames';
import {
sanitizeListRestProps,
useListContext,
useVersion,
DatagridHeaderCell,
DatagridLoading,
DatagridBody,
useDatagridStyles
} from 'react-admin';
/**
* The Datagrid component renders a list of records as a table.
* It is usually used as a child of the <List> and <ReferenceManyField> components.
*
* Props:
* - rowStyle
*
* @example Display all posts as a datagrid
* const postRowStyle = (record, index) => ({
* backgroundColor: record.nb_views >= 500 ? '#efe' : 'white',
* });
* export const PostList = (props) => (
* <List {...props}>
* <Datagrid rowStyle={postRowStyle}>
* <TextField source="id" />
* <TextField source="title" />
* <TextField source="body" />
* <EditButton />
* </Datagrid>
* </List>
* );
*
* @example Display all the comments of the current post as a datagrid
* <ReferenceManyField reference="comments" target="post_id">
* <Datagrid>
* <TextField source="id" />
* <TextField source="body" />
* <DateField source="created_at" />
* <EditButton />
* </Datagrid>
* </ReferenceManyField>
*/
const Datagrid = props => {
const classes = useDatagridStyles(props);
const {
body = <DatagridBody />,
children,
classes: classesOverride,
className,
expand,
hasBulkActions = false,
hover,
isRowSelectable,
rowClick,
rowStyle,
size = 'small',
...rest
} = props;
const {
basePath,
currentSort,
data,
ids,
loaded,
onSelect,
onToggleItem,
resource,
selectedIds,
setSort,
total,
} = useListContext(props);
const version = useVersion();
const updateSort = useCallback(
event => {
event.stopPropagation();
const newField = event.currentTarget.dataset.field;
const newOrder =
currentSort.field === newField
? currentSort.order === 'ASC'
? 'DESC'
: 'ASC'
: event.currentTarget.dataset.order;
setSort(newField, newOrder);
},
[currentSort.field, currentSort.order, setSort]
);
const handleSelectAll = useCallback(
event => {
if (event.target.checked) {
const all = ids.concat(
selectedIds.filter(id => !ids.includes(id))
);
onSelect(
isRowSelectable
? all.filter(id => isRowSelectable(data[id]))
: all
);
} else {
onSelect([]);
}
},
[data, ids, onSelect, isRowSelectable, selectedIds]
);
/**
* if loaded is false, the list displays for the first time, and the dataProvider hasn't answered yet
* if loaded is true, the data for the list has at least been returned once by the dataProvider
* if loaded is undefined, the Datagrid parent doesn't track loading state (e.g. ReferenceArrayField)
*/
if (loaded === false) {
return (
<DatagridLoading
classes={classes}
className={className}
expand={expand}
hasBulkActions={hasBulkActions}
nbChildren={React.Children.count(children)}
size={size}
/>
);
}
/**
* Once loaded, the data for the list may be empty. Instead of
* displaying the table header with zero data rows,
* the datagrid displays nothing in this case.
*/
if (loaded && (ids.length === 0 || total === 0)) {
return null;
}
const all = isRowSelectable
? ids.filter(id => isRowSelectable(data[id]))
: ids;
/**
* After the initial load, if the data for the list isn't empty,
* and even if the data is refreshing (e.g. after a filter change),
* the datagrid displays the current data.
*/
return (
<Table
className={classnames(classes.table, className)}
size={size}
{...sanitizeListRestProps(rest)}
>
<TableHead className={classes.thead}>
<TableRow
className={classnames(classes.row, classes.headerRow)}
>
{expand && (
<TableCell
padding="none"
className={classnames(
classes.headerCell,
classes.expandHeader
)}
/>
)}
{hasBulkActions && (
<TableCell
padding="checkbox"
className={classes.headerCell}
>
<Checkbox
className="select-all"
color="primary"
checked={
selectedIds.length > 0 &&
all.length > 0 &&
all.every(id => selectedIds.includes(id))
}
onChange={handleSelectAll}
/>
</TableCell>
)}
{Children.map(children, (field, index) =>
isValidElement(field) ? (
<DatagridHeaderCell
className={classes.headerCell}
currentSort={currentSort}
field={field}
isSorting={
currentSort.field ===
(field.props.sortBy ||field.props.source)
}
key={field.props.source || index}
resource={resource}
updateSort={updateSort}
/>
) : null
)}
</TableRow>
</TableHead>
{cloneElement(
body,
{
basePath,
className: classes.tbody,
classes,
expand,
rowClick,
data,
hasBulkActions,
hover,
ids,
onToggleItem,
resource,
rowStyle,
selectedIds,
isRowSelectable,
version,
},
children
)}
</Table>
);
};
Datagrid.propTypes = {
basePath: PropTypes.string,
body: PropTypes.element,
children: PropTypes.node.isRequired,
classes: PropTypes.object,
className: PropTypes.string,
currentSort: PropTypes.shape({
field: PropTypes.string,
order: PropTypes.string,
}),
data: PropTypes.object,
// @ts-ignore
expand: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
hasBulkActions: PropTypes.bool,
hover: PropTypes.bool,
ids: PropTypes.arrayOf(PropTypes.any),
loading: PropTypes.bool,
onSelect: PropTypes.func,
onToggleItem: PropTypes.func,
resource: PropTypes.string,
rowClick: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
rowStyle: PropTypes.func,
selectedIds: PropTypes.arrayOf(PropTypes.any),
setSort: PropTypes.func,
total: PropTypes.number,
version: PropTypes.number,
isRowSelectable: PropTypes.func,
};
export default Datagrid;
Upvotes: 1