-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[data grid] Smart children selection when toggling a group #4248
Comments
Hi, Thank's for your contribution For your 2nd point, I don't think we should change the return format of |
Suppose we have these rows |
It breaks because if you are controlling the model, the selected rows are the one you give back to the grid. This as several impacts
In v6, we will have to rework the selection to do #208 In v5, you can easily filter out the IDs of the group before using your model for something custom. // Remove all the rows generated by the grid
// With the Tree Data it would remove the auto generated parents but not the one based on real rows
// With the Aggregation (not released yet), it would remove the aggregation rows
const modelWithoutGroups = selectionModel.filter(id => !apiRef.current.getRowNode(id)?.isAutoGenerated)
// Remove all the rows that are not leaves (ie all the grouping rows)
// With the Tree Data it would remove all the rows that are not of maximal depth (not very usable I think)
// With the Aggregation (not released yet), it would not remove the aggregation rows
const depth = gridRowTreeDepthSelector(apiRef)
const modelWithoutGroups = selectionModel.filter(id => apiRef.current.getRowNode(id)?.depth === depth - 1) |
Fair enough, but could we at least have a method in the api that fetches the rows ids of a given group id? Maybe something like: |
Here is a method that retrieves all the leaves (filtered or not) of a group: https://codesandbox.io/s/datagridpro-v5-quick-start-forked-ltkt4g?file=/src/App.tsx We could probably add a built-in version of this method at some point. |
See #4270 for the method returning the rows of a group. |
Yes, internally the group row would never be selected, but its selection state would be based on its children. Or we even keep it selectable, being present in
We have this same problem with the "Select All" checkbox. |
I ran into this issue in development and wrote a gist that may be helpful for adding this feature, or anyone who needs it working: https://gist.github.com/inflrscns/fa5f3d4551947cbf4735ac8373d9bbef note: I built this for single column row grouping, probably doesn't work for multiple |
@inflrscns I've built on your code example to display indeterminate-state checkboxes in the parent rows whenever the children are partially selected, by adding the following column definition (my tree is only of depth 2, but this could be extended to support higher depths): import {
GRID_CHECKBOX_SELECTION_COL_DEF, GridCellCheckboxRenderer, GridColDef,
GridApiPro, selectedIdsLookupSelector
} from "@mui/x-data-grid-pro";
const checkboxColumn: GridColDef = {
...GRID_CHECKBOX_SELECTION_COL_DEF,
renderCell: (params: GridRenderCellParams) => {
const rowNode = params.rowNode;
const selectionLookup = selectedIdsLookupSelector(params.api.state, params.api.instanceId);
const indeterminate = rowNode.children != null && rowNode.parent == null &&
rowNode.children.some(child => selectionLookup[child] === undefined) &&
rowNode.children.some(child => selectionLookup[child] !== undefined);
return <GridCellCheckboxRenderer
{...params}
// @ts-ignore
indeterminate={indeterminate}
size={rowNode.parent == null ? undefined : 'small'}
/>
}
}; |
Further building off @HansBrende if you want the selection logic in the cell 2 things to note:
Otherwise this is working surprising well for me. import {
GRID_CHECKBOX_SELECTION_COL_DEF,
GridCellCheckboxRenderer,
GridColDef,
GridRenderCellParams,
selectedIdsLookupSelector
} from "@mui/x-data-grid-premium";
import { GridRenderCellParamsPremium } from "@mui/x-data-grid-premium/typeOverloads";
export const MUICustomCheckboxColumn: GridColDef = {
...GRID_CHECKBOX_SELECTION_COL_DEF,
renderCell: (params: GridRenderCellParams & GridRenderCellParamsPremium) => {
const rowNode = params.rowNode;
const selectionLookup = selectedIdsLookupSelector(params.api.state, params.api.instanceId);
let indeterminate: boolean | undefined = undefined;
let checked: boolean | undefined = undefined;
const extraData ={};
if (rowNode.type === "group") {
const isBottomGroup = rowNode.children != null && (rowNode.parent == null || rowNode.parent === "auto-generated-group-node-root");
indeterminate = isBottomGroup &&
rowNode.children.some(child => selectionLookup[child] === undefined) &&
rowNode.children.some(child => selectionLookup[child] !== undefined);
checked = isBottomGroup && rowNode.children.every(child => selectionLookup[child] !== undefined);
if(indeterminate){
extraData["indeterminate"]=indeterminate;
}
if(checked){
extraData["checked"]=checked;
}
extraData["onClick"] = (e) => {
if (rowNode.type === "group") {
if (rowNode.children) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
params.api.selectRows(rowNode.children, indeterminate || !checked);
}
e.preventDefault();
}
}
}
return <GridCellCheckboxRenderer
{...params}
{...extraData}
/>;
}
}; |
Wanted to make a quick note, it's not as clean, so I'm treating it separately, rather then editing what I did above. If you do what I'm doing, an issue I discovered was that the selected row count is counting the groups as selected if you use the select all header button. To stop that you can add isRowSelectable: (params)=>{
return params.id.indexOf('auto-generated-row-') === -1
}, to your grid...this will disable selecting it. Which also mean it marks it as disabled in the code that I gave above (you can no longer click it). to fix that you can add a single line to the example above. if (rowNode.type === "group") {
...
extraData["disabled"] = false;
... This will overwrite the disabled attribute on the grouping checkbox which will no longer count as selected in the footer etc. |
@cstephens-cni your examples have been of tremendous help to me so here's a slightly cleaned up version with the removal of const checkboxColumn = {
...GRID_CHECKBOX_SELECTION_COL_DEF,
renderCell: (
params: GridRenderCellParams & GridRenderCellParamsPremium
) => {
const { rowNode } = params;
if (rowNode.groupingField == null)
return <GridCellCheckboxRenderer {...params} />;
const selectionLookup = selectedIdsLookupSelector(
apiRef.current.state,
apiRef.current.instanceId
);
const isBottomGroup =
rowNode.children != null &&
(rowNode.parent == null ||
rowNode.parent === 'auto-generated-group-node-root');
const indeterminate =
isBottomGroup &&
rowNode?.children?.some(
(child) => selectionLookup[child] === undefined
) &&
rowNode.children.some((child) => selectionLookup[child] !== undefined);
const checked =
isBottomGroup &&
rowNode?.children?.every(
(child) => selectionLookup[child] !== undefined
);
const extraData: GridRenderCellParams &
GridRenderCellParamsPremium & {
indeterminate?: boolean;
checked?: boolean;
disabled?: boolean;
onClick?: (e: MouseEvent) => void;
} = {
...params,
disabled: false,
onClick: (e) => {
if (rowNode.groupingField != null) {
if (rowNode.children) {
apiRef.current.selectRows(
rowNode.children,
indeterminate || !checked
);
}
e.preventDefault();
}
},
indeterminate,
checked,
};
return <GridCellCheckboxRenderer {...extraData} />;
},
}; |
Before the row grouping on the MUI So here is the solution for anyone who is still using the tree data feature on the MUI
I tried to implement those two steps but apparently, nothing happens after the parent/group checkbox is clicked. |
DataGrid Checkbox Nested Group Intermediate
|
Now what it's missing is the ability to update after a filter is applied. |
TreeView is also aiming to support this feature soon, so it'd be good for us to keep aligned on the DevEx. |
It looks like possibly v7 may have broken this workaround. It seems this workaround is relying on every checkbox cell re-rendering any time there are changes to the selection state, but in v7 it seems that it's only re-rendering the checkbox cells that changed selection state - so any cell that needs to show as indeterminate isn't updated because it didn't change selection state according to the grid. I have a reproduction at the following link, where if you click a sub-group it will correctly select its children but not render its parent as indeterminate until an update on that row occurs (such as expanding or collapsing that row). https://react-kckdew.stackblitz.io Is there something I'm missing here? |
Hey , [data grid] Smart children selection when toggling a group #4248 |
This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue. Note We value your feedback @elyesbenabdelkader! How was your experience with our support team? |
Summary 💡
When you group rows and then select the group header row, I would expect:
Examples 🌈
Motivation 🔦
Having to manually look for a group rows on selection is (in my own opinion) an unnecessarily difficult task in the current state. Add to that if you deselect group rows (while selecting other rows), the task becomes even harder.
Order ID 💳 (optional)
No response
Other user requests
The text was updated successfully, but these errors were encountered: