-
-
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
[DataGrid] Completely customised UI for (server-based) filterering #9782
Comments
You need to override the filter menu item and the column header filter icon. In https://mui.com/x/react-data-grid/column-menu/#overriding-default-menu-items there's an example for the first customization. Additionally, you need to enable the server-side filtering mode and pass some import * as React from "react";
import {
unstable_composeClasses as composeClasses,
unstable_useId as useId
} from "@mui/utils";
import MenuItem from "@mui/material/MenuItem";
import Badge from "@mui/material/Badge";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import IconFilter from "@mui/icons-material/FilterAlt";
import { styled } from "@mui/system";
import {
DataGrid,
GridColumnMenu,
GridColumnMenuProps,
GridColumnMenuItemProps,
useGridApiContext,
ColumnHeaderFilterIconButtonProps,
useGridRootProps
} from "@mui/x-data-grid";
import { useDemoData } from "@mui/x-data-grid-generator";
function CustomFilterItem(props: GridColumnMenuItemProps) {
const { onClick, colDef } = props;
const apiRef = useGridApiContext();
const handleClick = React.useCallback(
(event: React.MouseEvent<HTMLElement>) => {
onClick(event);
apiRef.current.toggleColumnMenu(colDef.field);
},
[apiRef, colDef.field, onClick]
);
return (
<MenuItem onClick={handleClick}>
<ListItemIcon>
<IconFilter fontSize="small" />
</ListItemIcon>
<ListItemText>Show Filters</ListItemText>
</MenuItem>
);
}
function CustomColumnMenu(
props: GridColumnMenuProps & { showFilterPanel: () => void }
) {
const { showFilterPanel, ...other } = props;
return (
<GridColumnMenu
{...other}
slots={{
// Override slot for `columnMenuFilterItem`
columnMenuFilterItem: CustomFilterItem
}}
slotProps={{
columnMenuFilterItem: {
onClick: props.showFilterPanel
}
}}
/>
);
}
declare module "@mui/x-data-grid" {
interface ColumnMenuPropsOverrides {
showFilterPanel: () => void;
}
interface ColumnHeaderFilterIconButtonPropsOverrides {
showFilterPanel: () => void;
}
}
const GridIconButtonContainerRoot = styled("div", {
name: "MuiDataGrid",
slot: "IconButtonContainer"
})(() => ({
display: "flex",
visibility: "hidden",
width: 0
}));
function CustomFilterIcon(
props: ColumnHeaderFilterIconButtonProps & { showFilterPanel: () => void }
) {
const { counter, field, onClick, showFilterPanel } = props;
const apiRef = useGridApiContext();
const rootProps = useGridRootProps();
const labelId = useId();
const panelId = useId();
const toggleFilter = React.useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
event.stopPropagation();
showFilterPanel();
},
[apiRef, field, onClick, panelId, labelId]
);
if (!counter) {
return null;
}
const iconButton = (
<rootProps.slots.baseIconButton
id={labelId}
onClick={toggleFilter}
color="default"
aria-label={apiRef.current.getLocaleText("columnHeaderFiltersLabel")}
size="small"
tabIndex={-1}
aria-haspopup="menu"
{...rootProps.slotProps?.baseIconButton}
>
<rootProps.slots.columnFilteredIcon fontSize="small" />
</rootProps.slots.baseIconButton>
);
return (
<rootProps.slots.baseTooltip
title={
apiRef.current.getLocaleText("columnHeaderFiltersTooltipActive")(
counter
) as React.ReactElement
}
enterDelay={1000}
{...rootProps.slotProps?.baseTooltip}
>
<GridIconButtonContainerRoot className="MuiDataGrid-iconButtonContainer">
{counter > 1 && (
<Badge badgeContent={counter} color="default">
{iconButton}
</Badge>
)}
{counter === 1 && iconButton}
</GridIconButtonContainerRoot>
</rootProps.slots.baseTooltip>
);
}
export default function OverrideColumnMenuGrid() {
const { data } = useDemoData({
dataSet: "Commodity",
rowLength: 20,
maxColumns: 5
});
const showFilterPanel = () => {
console.log("showFilterPanel");
};
return (
<div style={{ height: 400, width: "100%" }}>
<DataGrid
{...data}
slots={{
columnMenu: CustomColumnMenu,
columnHeaderFilterIconButton: CustomFilterIcon
}}
slotProps={{
columnMenu: {
showFilterPanel
},
columnHeaderFilterIconButton: {
showFilterPanel
}
}}
filterModel={{
items: [
{ id: 0, field: "commodity", value: "a", operator: "contains" }
]
}}
filterMode="server"
/>
</div>
);
} Is this what you're looking for? |
Thank you very much for the example. I will test this for my use cases and post the results. |
Sorry, I must somehow have overlooked the concept of "Overwriting components". Given that this customisation is not trivial, it might still be worth exploring a simpler API to fully customise the filter panel. I imagine a single optional |
Glad it worked for you. Thanks for the suggestion about the API. What would you think the purpose would be for the |
Although the customization of column filters in the ˋDataGridˋ is quite extensive, there are situation when a completely customized UI for filtering is needed. In my use case we only filter on the backend and allow complex column specific filtering including boolean operators, ranges, validations and so on. |
If you are looking for something like this, I believe we don't need to introduce a dedicated prop for this, it's achievable without it. You could have a filter panel and use the grid API methods to control how it interacts with the Grid. You could also customize how default filter UI options work.
Would this work for you? |
Thank you for the feedback! |
Thank you for the clarification. Yes we do recognize that customizing the current filter panel isn't a piece of cake right now. We have this in our roadmap to make it possibly make it a bit easier to do so. |
Duplicates
Latest version
Summary 💡
The DataGrid offers an impressive list of options to customise filtering, but unfortunately sometimes a completely customised UI is needed. I'm looking for a way to intercept the actual entry points into the filtering to use my existing filtering solution.
I have a use case where the filtering is done on the server using a custom filter UI for each individual data set.
The filter UI is completely externalised and does already exist and I would need to make the DataGrid use the existing filter dialogs.
Assuming that only the UI to invoke filtering offered by the DataGrid is used and the rest is custom implemented , only two callbacks (that I cannot find) would be needed:
Additionally it would only be needed to set the number of active filters for each column, so the UI can be initialised whin the predefined filter definition.
Assuming that the DataGrid would allow me call my custom code when the user invokes the above functions, it should be possible to add a customised filtering logic in a very generic way.
Examples 🌈
Motivation 🔦
I have spend quite some time investigating all the available customisation options in DataGrid and am quite impressed.
Unfortunately when a completely customised filter UI is needed this currently does not seem to be possible.
As far as I understand it should be possible to completely customise the filtering by simply hooking into the entry points when setting or changing a filter.
Order ID 💳 (optional)
No response
The text was updated successfully, but these errors were encountered: