React-Table v8 - cell value but not from the row? - reactjs

I have my array and I have no problem getting what I need using the accessorFn... but in the cell render I'm trying to populate a variable that is in another object and not in the data array used to by the react-table.
const defaultColumns = [
{
accessorKey: "Traveler",
header: "Traveler",
accessorFn: (row) => `${row.LTAGNAME} ${row.FTAGNAME} (${row.EMPNUM})`,
cell: (props) => (
<Link to={`/${group.ID}/registrant/${props.row.original.id}`}>
{props.getValue()}
</Link>
),
size: 290,
},
{group.ID} is a separate object in React unrelated to the data being passed into the useReactTable function. Is it possible to reference something outside of the "data" ?

Related

Mui DataGrid > renderCell > useValue from renderCell

I have a field in the Datagrid with renderCell. The Value i have to display will be fetched inside the AlertIssues-Component as the original Data just provides the uuid to fetch the corresponding data (issue amount). So props.row._id is use in AlertIssues with a hook to retrieve the issues of the Alert in this row.
{
field: "issues",
type: "number",
headerClassName: "iconHeader",
// valueFormatter: params => {
// console.log("value formater",params )
// useGetIssueValue cannot be used here: (hook rules)
// let theValue = useGetIssueValue(params.id)
// return theValue
// },
// useGetIssueValue cannot be used here: (hook rules)
// valueGetter: params => useGetIssueValue(params.id)
renderCell: (props: GridRenderCellParams<Number>) => {
// useGetIssueValue is used inside AlertIssues
// and works to display the right amount
return(
<AlertIssues {...props} />
)},
},
export const AlertIssues = (props: GridRenderCellParams<Number>) => {
const { row } = props;
// i am getting my amount here without trouble.
// but it is just the displayed value ...
const alertIssueAmount = useGetIssueValue(row.id);
...
return <>alertIssueAmount</>
i tried to use "valueGetter" or "valueFormatter" to get the amount i need. but inside these functions i am not allowed to call my useData-hook, as they are functions and not React-Components or Hooks.
the row itself does not have the value i got inside of AlertIssues...
i am very lost here, how can i retrieve my issueAmount-value from the hook and use it in Datagrid? (e.g. for filter and sort)

React Table - setting up a collapsible row of data

I am currently trying to implement React-Table, with a data structure which matches this typescript definition.
export type VendorContent = {
id: number;
name: string;
user_name: string;
dob: string;
};
export type VendorData = {
vendor: string;
rows: VendorContent[];
};
<DataTable defaultData={vendorData} />
Structurally, the design I have looks like this:
Within the DataTable itself, I have something like this:
const columns = [
columnHelper.display({
id: 'actions',
cell: (props) => <p>test</p>,
}),
columnHelper.accessor('name', {
header: () => 'Name',
cell: (info) => info.renderValue(),
}),
columnHelper.accessor('user_name', {
header: () => 'User name',
cell: (info) => info.renderValue(),
}),
columnHelper.accessor('dob', {
header: () => 'DOB',
cell: (info) => info.renderValue(),
}),
];
const DataTable = (props: DataTableProps) => {
const { defaultData } = props;
const [data, setData] = React.useState(() =>
defaultData.flatMap((item) => item.rows)
);
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
Now, here's the kicker. Vendor1, and Vendor2 are collapsible rows, and need to be somehow passed into the table, but the defaultData.flatMap((item) => item.rows) which sets up each row, is obviously removing this information / structure. Ergo, I've nothing to hook into to try and render that in the table.
Things I've tried:
const [data, setData] = React.useState(() =>
defaultData
);
Once I try and pass the full Data object in, the column definition complains. (Data passed is no longer an array).
getSubRows within the React Table hook seems to require a full definition of all the columns (all I want is the vendor name there).
Header groups seem to be rendered before the headings, but what I actually want is almost a 'row group' that is expandable / collapsible?
How would I achieve a design similar to the below, with a data structure as illustrated, such that there are row 'headings' which designate the vendor?
I've setup a codesandbox here that sort of illustrates the problem: https://codesandbox.io/s/sad-morning-g5is0e?file=/src/App.js
First steps
Starting from this docs and this example from docs we can create a colapsable row like this (click on the vendor to expand/collapse next rows).
Steps to do it:
Import useExpanded and add it as the second argument of useTable (after the object containing { columns, data })
Replace defaultData.flatMap((item) => item.rows) with myData.map((row) => ({ ...row, subRows: row.rows })) (or if you can just rename rows to subRows and you can just send defaultData (without any mapping or altering of the data).
Add at the beginning of const columns = React.useMemo(() => [ the following snippet:
{
id: "vendor",
Header: ({ getToggleAllRowsExpandedProps }) => (
<span {...getToggleAllRowsExpandedProps()}>VENDOR</span> // this can be changed
),
Cell: ({ row }) =>
row.original.vendor ? <span {...row.getToggleRowExpandedProps({})}>row.vendor</span> : null, // render null if the row is not expandable
},
4. Add the DOB to the columns
Formatting the rows
With some reverse engineering from this question (using colspan) we can render only one value per row (reverse because we want the main row to use all 4 cells).
This will also make the first header part very small and lead to something like this for example.
How we got here from First steps:
We rendered the first cell if the original row has any value for vendor key and
We expanded the cell (in this case) for a span of 4 rows
Main difference in a snippet:
{
row.original.vendor ? (
<td {...row.cells[0].getCellProps()} colSpan={4}>
{row.cells[0].render("Cell")}
</td>
) : (
row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render("Cell")}</td>;
})
);
}
Unfortunately I don't think there is another (easier / more straight forward) way to do it (I mean I don't think this is bad, but I think it can be confusing especially if you try to figure it out searching trough so many pages of docs and there is no guide in this direction as far as I know).
Also please note I tried to highlight and explain the process. There might be some small extra adjustments needed in the code.

How to change id of tanstack React Table useSelectRow

Hi guy I just do experiment on build bulk delete on tanstack React Table
the problem is here I can't change the id of the selected column
why do I want to change this?
because I want MongoDB id that can send to the server.
with selectedRowIds method
here some code from hook
hooks => {
hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// accessor: '_id',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => {
console.log(row)
return <div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
},
},
...columns,
])
and all full reference comes from the main documentation
use selectedFlatRows is contian all selected row data
There is an option you can pass to the useReactTable hook called getRowId that allows you to customize your row id.
getRowId?: (
originalRow: TData,
index: number,
parent?: Row<TData>
) => string
https://tanstack.com/table/v8/docs/api/core/table#getrowid

Conditionally rendering cell data based on accessor value

Just started using react-table, trying to figure out how to conditionally render something based on the accessor value. I get back some data from an api call and use one of the values for the accessor.
{
Header: "Action",
id: "startTime",
accessor: "attributes.startTime"
}
So I have a column with header "Action", here I want to conditionally render a button if the accessor value attrbiutes.startTime === null or something along those lines.
Rendering of the UI occurs in a different file so I also need to access it there for handling button onClick
I have a codesandbox here with a working example.
You can use custom cell renderer
const columns = [
{
Header: "Action",
id: "startTime",
accessor: "attributes.startTime",
Cell: props => {
return props.value === null ? <button>Click Me </button> : props.value;
}
}
];

Delete particular item in React Table?

Header: "Delete",
id:'delete',
accessor: str => "delete",
Cell: (row)=> (
<span onClick={(row) => this.onRemoveHandler(row,props)} style={{cursor:'pointer',color:'blue',textDecoration:'underline'}}>
Delete
</span>
)
React Table
This is related to the header delete span link.The code snippets shows the render the delete label with hyperlink.
Here once a user click on delete link how can I get the id of that particular row.
ID has been already assgined to all the row from the json data.
So,How to pass the cellInfo or rowInfo inside the onClick function .
If you check out the docs (specificaly under 'Renderers'), the row object the cell receives is in the following format:
{
// Row-level props
row: Object, // the materialized row of data
original: , // the original row of data
index: '', // the index of the row in the original array
viewIndex: '', // the index of the row relative to the current view
level: '', // the nesting level of this row
nestingPath: '', // the nesting path of this row
aggregated: '', // true if this row's values were aggregated
groupedByPivot: '', // true if this row was produced by a pivot
subRows: '', // any sub rows defined by the `subRowKey` prop
// Cells-level props
isExpanded: '', // true if this row is expanded
value: '', // the materialized value of this cell
resized: '', // the resize information for this cell's column
show: '', // true if the column is visible
width: '', // the resolved width of this cell
maxWidth: '', // the resolved maxWidth of this cell
tdProps: '', // the resolved tdProps from `getTdProps` for this cell
columnProps: '', // the resolved column props from 'getProps' for this cell's column
classes: '', // the resolved array of classes for this cell
styles: '' // the resolved styles for this cell
}
Depending on what your input data looks like, you can use this information to delete from the dataset. If you plan on dynamically editing your data, you should store it in the state, so that the table component can update according to your edits. Assuming that in your state, you save your dataset as data, and use that to populate the table, you can alter the state in your onclick function:
Header: "Delete",
id:'delete',
accessor: str => "delete",
Cell: (row)=> (
<span onClick={() => {
let data = this.state.data;
console.log(this.state.data[row.index]);
data.splice(row.index, 1)
this.setState({data})
}}>
Delete
</span>
)
so a rough approximation of your app would like this:
this.state = {
data: <your data set>
}
<ReactTable
data={this.state.data}
columns={[
<other columns you have>,
{
Header: "Delete",
id:'delete',
accessor: str => "delete",
Cell: (row)=> (
<span style={{cursor:'pointer',color:'blue',textDecoration:'underline'}}
onClick={() => {
let data = this.state.data;
console.log(this.state.data[row.index]);
data.splice(row.index, 1)
this.setState({data})
}}>
Delete
</span>
)}
]}
/>
And of course, you don't need to log that row to the console, that doesn't need to be there. This is also just the quickest and easiest way to handle it, you could instead use the row object to get any specific element you want (id, name, etc.) and use that to remove from the dataset
An important note though: There is a big difference between viewIndex and index, index is what you want to use for your specific case
If you are like me and are using React-Table v7 and you are also using a hooks based approach in your components you will want to do it this way.
const [data, setData] = useState([]);
const columns = React.useMemo(
() => [
{
Header: 'Header1',
accessor: 'Header1Accessor',
},
{
Header: 'Header2',
accessor: 'Header2Accessor',
},
{
Header: 'Delete',
id: 'delete',
accessor: (str) => 'delete',
Cell: (tableProps) => (
<span style={{cursor:'pointer',color:'blue',textDecoration:'underline'}}
onClick={() => {
// ES6 Syntax use the rvalue if your data is an array.
const dataCopy = [...data];
// It should not matter what you name tableProps. It made the most sense to me.
dataCopy.splice(tableProps.row.index, 1);
setData(dataCopy);
}}>
Delete
</span>
),
},
],
[data],
);
// Name of your table component
<ReactTable
data={data}
columns={columns}
/>
The important part is when you are defining your columns make sure that the data in your parent component state is part of the dependency array in React.useMemo.

Resources