I am using ag-grid and I would like to pass the type of the data the component expects. When I pass in a type, I get an error message:
Expected 0 type arguments, but got 1. The component composes AgGridReact using forwardRef.
How do I pass in a type without encountering an error or how do I modify the Table component to accept generic types?
This is my code:
App.tsx
import * as React from 'react';
import { AgGridReact } from 'ag-grid-react';
import { ColDef, ColGroupDef } from 'ag-grid-enterprise';
import { GridOptions } from 'ag-grid-community';
import {
FirstDataRenderedEvent,
GridReadyEvent,
} from 'ag-grid-community/dist/lib/events';
import Table from './Table';
import './style.scss';
export interface ITerritoriesByZip {
TERR_ID: string;
TERR_NAME: string;
FULL_NAME: string;
WORK_EMAIL: string;
OFFICE_PHONE: string;
MOBILE_PHONE: string;
ADDRESS1: string;
CITY: string;
STATE: string;
ZIP: string;
}
export const columnDefs: (ColDef | ColGroupDef)[] = [
{
headerName: 'TERR_ID',
field: 'TERR_ID',
},
{
headerName: 'TERR_NAME',
field: 'TERR_NAME',
},
{
headerName: 'Full Name',
field: 'FULL_NAME',
},
{
headerName: 'Work Email',
field: 'WORK_EMAIL',
},
{
headerName: 'Office Phone',
field: 'OFFICE_PHONE',
},
{
headerName: 'Mobile Phone',
field: 'MOBILE_PHONE',
},
{
headerName: 'Address 1',
field: 'ADDRESS1',
},
{
headerName: 'City',
field: 'CITY',
},
{
headerName: 'State',
field: 'STATE',
},
{
headerName: 'ZIP',
field: 'ZIP',
},
];
const gridOptions: GridOptions = {
alignedGrids: [],
defaultColDef: {
editable: true,
sortable: true,
resizable: true,
filter: false,
flex: 1,
minWidth: 100,
},
};
export default function App() {
const currentMainGridRef = React.useRef<AgGridReact<ITerritoriesByZip>>(null);
const data = [];
const onGridReady = React.useCallback((params: GridReadyEvent) => {
params.api.sizeColumnsToFit();
}, []);
const onCurrentFirstDataRendered = React.useCallback(
(params: FirstDataRenderedEvent) => {
params.api.sizeColumnsToFit();
},
[]
);
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<Table<ITerritoriesByZip>
ref={currentMainGridRef}
rowData={data}
rowCount={data.length}
columnDefs={columnDefs}
isLoading={false}
isSuccess={true}
pagination={false}
onGridReady={onGridReady}
onFirstDataRendered={onCurrentFirstDataRendered}
gridOptions={gridOptions}
/>
</div>
);
}
Table.tsx
import { Box, LinearProgress, Typography } from '@mui/material';
import React, {
ForwardedRef,
forwardRef,
useEffect,
useMemo,
useState,
} from 'react';
import { AgGridReact } from 'ag-grid-react';
import {
AgGridReactProps,
AgReactUiProps,
} from 'ag-grid-react/lib/shared/interfaces';
import { has, isEmpty, isFunction, isNull, map } from 'lodash';
import { renderToStaticMarkup } from 'react-dom/server';
import { GridApi } from 'ag-grid-community/dist/lib/gridApi';
import { ColumnApi } from 'ag-grid-community/dist/lib/columns/columnApi';
import { GridOptions } from 'ag-grid-community';
import { ColumnState } from 'ag-grid-community/dist/lib/columns/columnModel';
import {
ColDef,
ColGroupDef,
} from 'ag-grid-community/dist/lib/entities/colDef';
import { GridReadyEvent } from 'ag-grid-community/dist/lib/events';
import CustomPagination from './PaginationRenderer';
interface ITable<T> extends AgGridReactProps, AgReactUiProps {
isLoading: boolean;
isSuccess: boolean;
id?: string;
pagination: boolean;
rowData?: T[] | null;
title?: string;
gridOptions?: GridOptions;
rowCount: number;
columnDefs?: (ColDef | ColGroupDef)[] | null;
onGridReady?: (params: GridReadyEvent) => void;
}
export interface AutoSizeRef {
autoSizeAll: () => void;
}
const AgGridTable = <T extends {}>(
props: ITable<T>,
ref: ForwardedRef<AgGridReact<T>>
) => {
const [colDefState, setColDefState] = useState<ColumnState[]>([]);
const autoSizeAll = (): void => {
if (ref != null && !isFunction(ref)) {
const allColumnIds = map(
(ref.current?.columnApi as ColumnApi).getColumns(),
(column) => {
return (column as any).getId();
}
);
(ref.current?.columnApi as ColumnApi).autoSizeColumns(
allColumnIds,
false
);
}
};
// useImperativeHandle(ref, () => ({
// autoSizeAll,
// }));
useEffect(() => {
if (
ref != null &&
!isFunction(ref) &&
!isNull(ref.current) &&
!isEmpty(ref.current) &&
has(ref.current, 'api')
) {
setTimeout(() => autoSizeAll(), 400);
}
}, [ref]);
const containerStyle = useMemo(() => ({ width: '100%', height: '100%' }), []);
const gridStyle = useMemo(() => ({ height: '100%', width: '100%' }), []);
const defaultExcelExportParams = useMemo(() => {
return {
allColumns: true,
};
}, []);
const { isLoading, pagination, id, isSuccess, onGridReady, ...rest } = props;
useEffect(() => {
if (ref != null && !isFunction(ref)) {
if (
isLoading &&
!isNull(ref.current) &&
!isEmpty(ref.current) &&
has(ref.current, 'api')
) {
(ref.current?.api as GridApi).showLoadingOverlay();
}
if (
isEmpty(props.rowData) &&
!isNull(ref.current) &&
!isEmpty(ref.current) &&
has(ref.current, 'api')
) {
(ref.current?.api as GridApi).showNoRowsOverlay();
}
}
}, [isLoading, ref, props.rowData]);
const onTableGridReady = (params: GridReadyEvent) => {
setColDefState(params.columnApi.getColumnState());
};
return (
<Box className="pt-2" style={containerStyle}>
{isLoading && <LinearProgress variant="indeterminate" />}
<Box className="ag-theme-alpine" id={id} style={gridStyle}>
<AgGridReact<T>
animateRows
ref={ref}
pagination={pagination}
domLayout="autoHeight"
paginationPageSize={100}
onGridReady={(params) => {
onTableGridReady(params);
if (onGridReady) {
onGridReady(params);
}
}}
suppressPaginationPanel
statusBar={{
statusPanels: [
{
statusPanel: CustomPagination,
statusPanelParams: {
dataCount: props.rowCount,
paginationEnabled: pagination,
},
},
],
}}
gridOptions={props.gridOptions}
defaultExcelExportParams={defaultExcelExportParams}
overlayLoadingTemplate={
'<span >Please wait while your rows are loading</span>'
}
{...rest}
/>
</Box>
</Box>
);
};
const Table = forwardRef(AgGridTable);
export default Table;
Stackblitz Link: Link.
Any help is appreciated.
CodePudding user response:
in Table.tsx do the following:
const TableRef = forwardRef(AgGridTable);
const Table = <T extends {}>({
myRef,
...rest
}: ITable<T> & { myRef: ForwardedRef<AgGridReact<T>> }) => (
<TableRef {...rest} ref={myRef} />
);
export default Table;
CodePudding user response:
Another option is to use wrapper:
const AgGridTable = <T extends {}>() => forwardRef<AgGridReact<T>, ITable<T>>((props, ref) => {...}
const Table = AgGridTable();
export default Table;