I have implemented Selection Aggregates to count content inside cells. For this I use the onSelectionChange prop, passing a selectionChange function that calls getStatusData from '@progress/kendo-react-grid' and stores the result in the statusData state.
Recently I added a requirement to highlight the row when I select a cell in that row, so I decided to use a custom row renderer via the rows prop and pass a row component.
But here’s the problem: as soon as I started using the custom row renderer, the double-click handling that used to work via the Grid's onRowDoubleClick stopped working. I tried handling the double-click directly on the <tr> by attaching an onDoubleClick handler, but that didn't help either.
As far as I can tell, the issue is that when I click a cell, onSelectionChange fires and I update the state with the result of getStatusData (which is necessary for Selection Aggregates). That state update causes my rows to re-render, and the double-click never fires. If I don't use a custom row renderer (which I need for row highlighting), I can attach onSelectionChange on the Grid, update the state on click for Selection Aggregates, and onRowDoubleClick works.
How can I combine Selection Aggregates, row highlighting when selecting a cell (currently implemented with the custom row renderer), and double-click handling?
Link for sandbox: https://codesandbox.io/p/sandbox/keen-andras-kyzf5c
Code:
import * as React from "react";
import {
Grid,
GridColumn as Column,
GridSelectionChangeEvent,
StatusBar,
getStatusData,
StatusItem,
GridCustomRowProps,
} from "@progress/kendo-react-grid";
import sampleProducts from "./gd-sample-products";
const DATA_ITEM_KEY = "ProductID";
const App = () => {
const [statusData, setStatusData] = React.useState<StatusItem[]>([
{ type: "count", formattedValue: "0", value: 0 },
]);
const selectionChange = (event: GridSelectionChangeEvent) => {
console.log("selectionChange single-click");
setStatusData(
getStatusData({
dataItems: sampleProducts,
target: event.target,
select: event.select,
dataItemKey: DATA_ITEM_KEY,
})
);
};
const CustomRow = (props: GridCustomRowProps) => {
// console.log("CustomRow props: ", props);
const available = !props.dataItem.Discontinued;
const noBgr = { backgroundColor: "" };
const customBgr = { backgroundColor: "lavender", fontWeight: "bold" };
return (
<tr
{...props.trProps}
style={available ? noBgr : customBgr}
onDoubleClick={(e) => console.log("CustomRow onDoubleClick e: ", e)}
onClick={(e) => {
console.log("CustomRow single click");
}}
>
{props.children}
</tr>
);
};
return (
<>
<div style={{ padding: "5px", color: "#999" }}>
<div>Ctrl+Click/Enter - add to selection</div>
<div>Shift+Click/Enter - select range </div>
</div>
<Grid
rows={{ data: CustomRow }}
onRowDoubleClick={(e) => console.log("onRowDoubleClick")}
data={sampleProducts}
autoProcessData={true}
dataItemKey={DATA_ITEM_KEY}
reorderable={true}
navigatable={true}
defaultSelect={{
4: [0],
5: [0],
6: [0],
7: [0],
}}
selectable={{ enabled: true, drag: true, cell: true, mode: "multiple" }}
onSelectionChange={selectionChange}
>
<Column title="Products">
<Column field="ProductID" title="Product ID" width="100px" />
<Column field="ProductName" title="Product Name" width="300px" />
<Column field="UnitsInStock" title="Units In Stock" />
<Column field="UnitsOnOrder" title="Units On Order" />
<Column field="ReorderLevel" title="Reorder Level" />
<Column field="Discontinued" title="Discontinued" />
<Column field="FirstOrderedOn" title="Date" format="{0:d}" />
</Column>
<StatusBar data={statusData} />
</Grid>
</>
);
};
export default App;
