react-admin - 有没有办法自定义datagrid的表头?
问题描述
我正在使用 react-admin 3.8.1
并且我正在处理自定义的表头以在下面实现 - UDI Key
我发现的是
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>
)
但这样我只能自定义数据网格的主体,而不是表头。
目前,唯一的方法似乎是改变 Datagrid.tsx 但我不想这样做。
如果有人知道解决方案。请让我知道,谢谢。
解决方案
React-admin<Datagrid>
不提供自定义表头的方法。<Datagrid>
除了使用自己的组件之外,您没有其他解决方案。
您可以将以下代码作为基础(从 react-admin 源复制,并从 TS 迁移到 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;
推荐阅读
- python - 是否有一个函数可以在 Python 中用一个符号替换多个符号?
- gatsby - Gatsby 中布局的条件渲染
- php - 为什么我不能将我的表单添加到我的 MySQL 数据库中?
- python - 如何将训练好的模型转换为函数?
- r - 无法使 sen2r 函数工作,缺少一些参数?
- javascript - 给定一个数组,编写一个返回该数组所有可能的三元组/序列的函数?JavaScript
- python - 仅支持有效的不记名身份验证 - Python - Spotify API
- ruby-on-rails - Heroku 环境变量未在 javascript 中为 React/Rails 应用程序设置
- sql - 使用 SQL 提取 XML 数据
- flutter - Flutter 从“Future”返回“Widget”
"