How to rerender entire single row in react-table? - reactjs

I have a react-table component in my app and pass there next props:
<ReactTable
data={this.props.words}
columns={columns}
getTrProps={changing_state_func}
/>
changing_state_func is a function that changes state of the component that wraps react-table. Specifically, this function fills an array that contains ids of the data objects for rows. So I'd like to highlight the rows with the data for those ids... Cannot figure it out how to do it with this particular datagrid. Maybe somebody has the experience working with react-table and example on this case.

I'm not sure what actually you're trying to do, but here are my thoughts.
getTrProps is used to pass props to the table's rows.
So according the module docs, you can pass whatever you want.
The example shows how you can change the color of the rows, those meet specific condition:
// Any Tr element will be green if its (row.age > 20)
<ReactTable
getTrProps={(state, rowInfo, column) => {
return {
style: {
background: rowInfo.age > 20 ? 'green' : 'red'
}
}
}}
/>

Fixes to the react-table 5.0.2 allow to have access to the table's instance, and the problem can be solved by calling .forceUpdate() method on the table's instance. changing_state_func in this case may look like this:
changing_state_func = (state, rowInfo, column, instance) => {
if (!rowInfo) return {}
return {
style: {
background: (this.state.rowsIdsArray.includes(rowInfo.row.id)) ? 'green' : null
},
onClick: () => {
this.setState({rowsIdsArray: this.state.rowsIdsArray.concat([rowInfo.row.id])});
instance.forceUpdate()
}
}
}
Thanks to the Tanner Linsley for responsiveness and quick fixes.

Related

How do I put a react jsx component within my ag-grid cells

Unfortunately I cannot share code because it is company confidential but I am basically using colDefs to define my columns within a React ag-grid and would like to have one column whose cells are all a custom JSX button component I built that will allow me to delete the row of the cell clicked as well as propagate changes elsewhere in the code. I have been stuck trying to use cellRenderers and simply cannot figure out how to add custom react functional components to the cell. If anyone can assist with this it would be greatly appreciated. I will try to provide as much additional context as needed but am unfortunately unable to share direct code snippets. Thanks!
You can see an example in ag-grid's documentation here. I've also put up a sandbox in which you can delete rows from the grid by clicking each respective button.
Basically you have to:
Create your custom renderer that will appear in the cells of the column, like the DeleteCellRenderer. You'll have to access at least 2 props:
props.context, the grid's context which will contain the method(s) to fire in the onClick method
props.data, which contains the data for that row - the specific item in the rowData array that is.
Open the component that renders the <AgGridReact /> component and import the renderer.
Declare the renderer in the grid's frameworkComponents prop, like this:
<AgGridReact
frameworkComponents={{
deleteCellRenderer: DeleteCellRenderer
}}
// ...
Declare your delete function to fire when clicking on the button, then pass it to the grid's context.
const handleDelete = (data) => {
// Your logic here
};
// ...
<AgGridReact
frameworkComponents={{
deleteCellRenderer: DeleteCellRenderer
}}
context={{ handleDelete }}
//...
Finally, insert the column in the colDef array containing the cellRenderer, either like this:
const colDef = [
//...
{
headerName: "delete"
cellRenderer: "deleteCellRenderer"
},
//...
];
Or, if you're using <AgGridColumn> components as children:
<AgGridReact
//...
>
<AgGridColumn headerName="Delete" cellRenderer="deleteCellRenderer" />
//...
</AgGridReact>

Conditional styling on row for dynamic cell value

Conditional row styling on ag grid where I want to do rowstyle on user choice of cell value
gridoptions.getRowStyle = function(params) {
if (params.node.data === 'cell value typed by user in external/custom component i.e outside grid') {
return { 'background': value selected by user in cutom componet outside grid };
}
}
#sandeep's answer works perfectly. I just want to chime in another way to solve the problem which is to use context. context is just another javascript object which contains any information that you want to share within AgGrid. The data will be accessible in most AgGrid callbacks for example cell renderers, editors's render callback and in your case getRowStyle callback
const sickDays = // data from external component
const color = // data from external component
<AgGridReact
getRowStyle={(params) => {
const { styles, data } = params.context;
if (params.node.data["sickDays"] === data.sickDays) {
return { backgroundColor: styles.color };
}
return null;
}}
context={{
data: { sickDays },
styles: { color }
}}
/>
Live Demo
here is a plunkr which should give you idea to solve the problem. since i don't know much about your component hence i used two input boxes with button to set background color to row but you can use complex styles as well.
I am using api.redrawRows() since the operation we are performing needs to work on row.

React Table using hooks expand and collapse rows

I am using react-table component inside my project. The row expansion property is something that my features utilized and it is working fine now.
I need the ability to collapse all the rows while I expand a row. ie Only one row should be open at a time. I did go through many documentation and stackoverflow links but none didn't work out. Please note that this implementation is using hooks. Just like the one mentioned here : https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/expanding
By default they allow to open more than one row at a time, but I need to implement the opposite.
The closest I came to is this : Auto expandable rows and subrows react table using hooks
But here its opening on initial load.
Thanks
I have only added a portion of App function here. Codesandbox: https://codesandbox.io/s/jolly-payne-dxs1d?fontsize=14&hidenavigation=1&theme=dark.
Note: I am not used to react-table library. This code is a sample that only works in the table with two levels of rows. You can optimize the code with recursion or some other way to make the code work in multi-level tables.
Cell: ({ row, rows, toggleRowExpanded }) =>
// Use the row.canExpand and row.getToggleRowExpandedProps prop getter
// to build the toggle for expanding a row
row.canExpand ? (
<span
{...row.getToggleRowExpandedProps({
style: {
// We can even use the row.depth property
// and paddingLeft to indicate the depth
// of the row
paddingLeft: `${row.depth * 2}rem`
},
onClick: () => {
const expandedRow = rows.find(row => row.isExpanded);
if (expandedRow) {
const isSubItemOfRow = Boolean(
expandedRow && row.id.split(".")[0] === expandedRow.id
);
if (isSubItemOfRow) {
const expandedSubItem = expandedRow.subRows.find(
subRow => subRow.isExpanded
);
if (expandedSubItem) {
const isClickedOnExpandedSubItem =
expandedSubItem.id === row.id;
if (!isClickedOnExpandedSubItem) {
toggleRowExpanded(expandedSubItem.id, false);
}
}
} else {
toggleRowExpanded(expandedRow.id, false);
}
}
row.toggleRowExpanded();
}
})}
>
{row.isExpanded ? "👇" : "👉"}
</span>
) : null

Toggle columns on react-bootstrap-table2

Using this library https://react-bootstrap-table.github.io/react-bootstrap-table2/
And this to toggle columns: https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Bootstrap%204&selectedStory=Column%20Toggle%20with%20bootstrap%204&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel
Docs on column toggle: https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-column-toggle.html
I need to know what columns have been hidden.
A callback is included for this:
onColumnToggle: Call this method when user toggle a column.
Implemented:
<ToolkitProvider
keyField="globalId"
data={ this.props.data }
columns={ this.state.columns }
columnToggle
>
{
props => {
return (
<>
<ToggleList {...props.columnToggleProps} onColumnToggle={this.columnToggle} className="d-flex flex-wrap"/>
<hr/>
<BootstrapTable
striped
bootstrap4
keyfield="globalId"
{...props.baseProps}
/>
</>
)
}
}
</ToolkitProvider>
My function this.columnToggle fires as expected. But the table itself is no longer hiding/showing columns. If I remove my function, it works again.
Updated:
The columnToggle function:
columnToggle = (column) => {
console.log(column); // outputs the toggled column
};
the ToggleList uses the render props design pattern, so it sends the original onColumnToggle
with the props you spread on the component ToggleList, but also, you provided your own copy of the onColumnToggle function, which will override the expected result.
a simple solution so you could take advantage of the two functionalities (the actual onColumnToggle of the Component, and your copy of it) by doing something like this:
<ToggleList {...props.columnToggleProps} onColumnToggle={() => {this.columnToggle(); props.columnToggleProps.onColumnToggle(/* whatever params it needs */)}} className="d-flex flex-wrap"/>
this will let you do custom things when the column toggles, and you still have the original functionality of the ToggleList API.
EDIT: The Problem with this solution, that the ToggleList component seems to be Un-controlled. so I would suggest using this example from the official docs.

How to fix pagination reset issue in react-table?

I am working for a feature where i have to apply a filter outside the component which is using react-table, but the current page number doesn't get reset after the filter is being applied. The result being fetched (have applied server-side pagination) shows the first page's data.
I have tried to use the callback onFetchData to change the current page number but it does'nt get triggered when the filter from outside the component is applied.
render() {
const { orders, onUpdate } = this.props;
const defaultPageSize = 50;
return (
<div className="admin-report-table">
<ReactTable
data={orders.ordersData}
columns={this.columns}
pages={Math.ceil(orders.count / defaultPageSize)}
defaultPageSize={defaultPageSize}
multiSort={false}
showPageSizeOptions={false}
showPaginationTop
className="-striped -highlight"
noDataText="No orders found. Please check your connection or change your filters."
filterable
manual // informs React Table that you'll be handling sorting and pagination server-side
onFetchData={(state) => {
const { page, pageSize, filtered, sorted } = state;
const adjustedPage = page + 1; // since library page starts from 0
onUpdate({
page: adjustedPage,
filtered,
pageSize,
sorted,
});
}}
/>
</div>
);
}
The Page number should be reset to 1 e.g. current display is Page 2 of 3, after the filter from outside the table is applied, the result is fetched and shown but the Page 2 of 3 doesn't change while the result in the table is of page 1.
Set autoResetPage: false
https://react-table.tanstack.com/docs/api/usePagination#table-options
its gonna avoid rendering all the time.
I had the same issue in my react table, in the solution for that, in the componentWillReceiveProps method I update the page props of the react-table and set it to the "0" when react-table gets new filtered data (Props changed ), its work for me fine, so in your code just set page props as 0 when your table get new data from the parent
componentWillReceiveProps(nextProps: Readonly<IProps>): void {
if (nextProps.properties !== this.props.properties && nextProps.properties.length > 0) {
this.setState({
selectedPageNumber : 0
})
}
}
This issue could be solved by the hacky solution found here: TroyWolf's solution.
And read the whole post there - it may be that your current case is in another comment. If the post will be removed somehow I post it here:
store a reference to the ReactTable's instance. It works to directly update myReactTableInstance.state.page = 0
With similar use cases, I have found its best to use once's own controlled page state for index, as mentioned here:
Check here as mentioned in the docs
It becomes simpler to handle the page reset actions on custom filtering/custom sorting, and trigger accordingly
I am using react table's out of the box pagination and the issue I had was how to extract the current pageIndex from react table. Because every time there was an action on the row of React table, that did not alter the no. of rows, the React table would go back to page 0.
Following worked for me, hacky but works -
On parent component calling React table -
signalTableData is where I have my data for columns and datarows. this could be your data.
const [pageIndex, setPageIndex] = useState(0);
<ReactTable
columns={signalTableData ? signalTableData.headerRow : <div>Loading...</div>}
data={signalTableData.dataRows ? signalTableData.dataRows : <div>Loading...</div>}
sortbyCollumn='originDate'
desc={true}
pageIndex = {pageIndex}
setPageIndex = {setPageIndex}
/>
One React Table js -
function Table({ columns, data, sortbyCollumn, desc, pageIndex, setPageIndex }) {...
and
useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
autoResetPage: false,
initialState: {
pageSize: 5,
pageIndex: pageIndex,
sortBy: [
{
id: sortbyCollumn,
desc: desc
}
] },
},

Resources