问题描述
我有一个表,该表必须显示从接收到的数据动态生成的任意数量的列。
我创建了一个列接口,该接口将保存我需要的每个列的所有属性,例如是否可以将列最小化(变窄),是否是必须从结构中呈现图标的列或为组行渲染特定数据等。
在材料表中,我试图映射这些列,但始终会收到错误: 错误:this.tableContainerDiv.current为空
即使对象列表与我对这些列进行硬编码时完全相同,也会发生这种情况。
我的(缩减)代码:
interface IColumnObject {
field: string;
title: string;
sorting: boolean;
minimizing: boolean;
minimized: boolean;
hidden: boolean;
width: string;
grouprender: boolean;
iconrender: boolean;
}
interface State {
detailData: ITableData[];
filteredData: ITableData[];
headers: IHeaderObject[];
columns: IColumnObject[];
filterList: IFilterList;
anchorEl: Element;
csvHeader: ICsvHeader[];
csvData: ICsvData[];
}
class DetailAllRoute extends React.Component<Props,State> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private csvLink: React.RefObject<any> = React.createRef();
...
public generateTableDetailData = () => {
const tableData: ITableData[] = [];
let createHeader = true;
let createColumn = true;
const headers: IHeaderObject[] = [];
const columns: IColumnObject[] = [];
...
// Add the Application,Filename and Location column objects to the columns list
const applicationColumn: IColumnObject = {
field: 'application',title: this.i18n.translatetoString('Column_Application'),sorting: true,minimizing: false,minimized: false,hidden: false,width: '100px',grouprender: false,iconrender: false,};
columns.push(applicationColumn);
const filenameColumn: IColumnObject = {
field: 'filename',title: this.i18n.translatetoString('Column_Filename'),width: '270px',grouprender: true,};
columns.push(filenameColumn);
const locationColumn: IColumnObject = {
field: 'location',title: this.i18n.translatetoString('Column_Location'),minimizing: true,width: '350px',};
columns.push(locationColumn);
...
}
render() {
const { classes } = this.props;
const {
compData,filteredData,columns,filterList,anchorEl,} = this.state;
return (
<React.Fragment>
<Paper className={classes.muiListRoot} style={{ backgroundColor: '#fff' }}>
<MaterialTable
title={
<span style={{ fontSize: '2.0em',fontWeight: 'bold',color: '#19768B' }}>
{`${this.i18n.translatetoString('Table_DetailData')} Test`}
</span>
}
actions={[
{
icon: FilterList,tooltip: 'Filter',position: 'toolbar',onClick: event => {
this.handlePopoverClick(event);
},},]}
components={{
// eslint-disable-next-line react/display-name
Header: headerprops => (
<React.Fragment>
{this.getTableHeader()}
<MTableHeader {...headerprops} />
</React.Fragment>
),}}
columns={columns.map(c => {
return {
title: c.title,field: c.field,sorting: c.sorting,width: c.width,hidden: c.hidden,} as Column<any>;
})}
data={filteredData}
parentChildData={(row,rows) => rows.find(a => a.application === row.parent)}
options={{
toolbar: true,exportButton: { csv: true },exportCsv: () => {
this.customExportCSV();
},headerStyle: {
backgroundColor: '#19768B',color: 'white',borderBottom: '1px solid black',// eslint-disable-next-line @typescript-eslint/no-explicit-any
rowStyle: (_data: any,index: number) => {
return index % 2 ? { backgroundColor: '#ecf2f9' } : {};
},}}
localization={{
pagination: {
labeldisplayedRows: this.i18n.translatetoString('String_RowFromToCount'),labelRowsSelect: this.i18n.translatetoString('String_Rows'),labelRowsPerPage: this.i18n.translatetoString('String_RowsPerPage'),firstAriaLabel: this.i18n.translatetoString('String_FirstPage'),firstTooltip: this.i18n.translatetoString('String_FirstPage'),prevIoUsAriaLabel: this.i18n.translatetoString('String_PrevPage'),prevIoUsTooltip: this.i18n.translatetoString('String_PrevPage'),nextAriaLabel: this.i18n.translatetoString('String_NextPage'),nextTooltip: this.i18n.translatetoString('String_NextPage'),lastAriaLabel: this.i18n.translatetoString('String_LastPage'),lastTooltip: this.i18n.translatetoString('String_LastPage'),toolbar: {
nRowsSelected: this.i18n.translatetoString('String_RowsSelected'),searchTooltip: this.i18n.translatetoString('String_Search'),searchPlaceholder: this.i18n.translatetoString('String_Search'),exportTitle: this.i18n.translatetoString('String_Export'),exportCSVName: this.i18n.translatetoString('String_ExportAs'),body: {
emptyDataSourceMessage: this.i18n.translatetoString('String_NoData'),}}
/>
</Paper>
<div>
<CSVLink
data={csvData}
headers={csvHeader}
filename="CSV_File.csv"
ref={this.csvLink}
target="_blank"
/>
</div>
</React.Fragment>
);
}
}
您知道我在映射中做错了什么吗?还是当使用地图生成列数组时,材料表不喜欢它?
当我用以下方式对列进行硬编码时:
...
columns={[
{
title: this.i18n.translatetoString('Column_Application'),field: 'application',hidden: true,{
title: this.i18n.translatetoString('Column_Filename'),field: 'filename',// eslint-disable-next-line react/display-name
render: rowData =>
!!!rowData.filename ? (
<span>
<b>{this.i18n.translatetoString('Column_Application')}: </b>
{rowData.application}
</span>
) : (
rowData.filename
),{
title: this.i18n.translatetoString('Column_Location'),field: 'location',]}
...
一切正常。但是我需要映射列,因为列是根据接收到的数据动态生成的。
解决方法
在大多数情况下,问题是程序员错误。我花了好一会儿才弄清楚,但最终得到了同事的帮助。在他的指导下,我终于设法弄清了问题的根源。
最后,我发现系统抛出错误,因为找不到列名。控制台中显示的(更高处)错误非常容易引起误解,因为它指出使用了无效的(空)引用,事实并非如此。由于某种未知的原因,我无意中没有在最后一步中使用生成的唯一列名,在该步骤中我添加了每一行的数据,而是使用了硬编码的列名。容易忽略,但是却很难咬...