Skip to content

Commit 3e18bc0

Browse files
ithrforuВладимир КолесниковMBilalShafim4theushw
authored
[DataGrid] Allow to customize the value displayed in the filter button tooltip (#6956)
Co-authored-by: Владимир Колесников <[email protected]> Co-authored-by: Bilal Shafi <[email protected]> Co-authored-by: Matheus Wichman <[email protected]>
1 parent b89fbdb commit 3e18bc0

File tree

7 files changed

+93
-2
lines changed

7 files changed

+93
-2
lines changed

docs/data/data-grid/filtering/CustomRatingOperator.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from 'react';
22
import PropTypes from 'prop-types';
33
import Box from '@mui/material/Box';
44
import Rating from '@mui/material/Rating';
5-
import { DataGrid } from '@mui/x-data-grid';
5+
import { DataGrid, GridToolbarFilterButton } from '@mui/x-data-grid';
66
import { useDemoData } from '@mui/x-data-grid-generator';
77

88
function RatingInputValue(props) {
@@ -88,6 +88,7 @@ const ratingOnlyOperators = [
8888
},
8989
InputComponent: RatingInputValue,
9090
InputComponentProps: { type: 'number' },
91+
getValueAsString: (value) => `${value} Stars`,
9192
},
9293
];
9394

@@ -118,6 +119,9 @@ export default function CustomRatingOperator() {
118119
<DataGrid
119120
{...data}
120121
columns={columns}
122+
components={{
123+
Toolbar: GridToolbarFilterButton,
124+
}}
121125
initialState={{
122126
...data.initialState,
123127
filter: {

docs/data/data-grid/filtering/CustomRatingOperator.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
DataGrid,
77
GridFilterItem,
88
GridFilterOperator,
9+
GridToolbarFilterButton,
910
} from '@mui/x-data-grid';
1011
import { useDemoData } from '@mui/x-data-grid-generator';
1112

@@ -62,6 +63,7 @@ const ratingOnlyOperators: GridFilterOperator[] = [
6263
},
6364
InputComponent: RatingInputValue,
6465
InputComponentProps: { type: 'number' },
66+
getValueAsString: (value: number) => `${value} Stars`,
6567
},
6668
];
6769

@@ -92,6 +94,9 @@ export default function CustomRatingOperator() {
9294
<DataGrid
9395
{...data}
9496
columns={columns}
97+
components={{
98+
Toolbar: GridToolbarFilterButton,
99+
}}
95100
initialState={{
96101
...data.initialState,
97102
filter: {

docs/data/data-grid/filtering/filtering.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ The [`valueFormatter`](/x/react-data-grid/column-definition/#value-formatter) is
203203
If the column has a [`valueGetter`](/x/react-data-grid/column-definition/#value-getter), then `params.value` will be the resolved value.
204204
:::
205205

206+
:::info
207+
The filter button displays a tooltip on hover if there are active filters. Pass [`getValueAsString`](/x/api/data-grid/grid-filter-operator/) in the filter operator to customize or convert the value to a more human-readable form.
208+
:::
209+
206210
In the demo below, you can see how to create a completely new operator for the Rating column.
207211

208212
{{"demo": "CustomRatingOperator.js", "bg": "inline", "defaultCodeOpen": false}}

docs/pages/x/api/data-grid/grid-filter-operator.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { GridFilterOperator } from '@mui/x-data-grid';
1717
| Name | Type | Default | Description |
1818
| :---------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1919
| <span class="prop-name">getApplyFilterFn</span> | <span class="prop-type">(filterItem: GridFilterItem, column: GridColDef&lt;R, V, F&gt;) =&gt; null \| ((params: GridCellParams&lt;R, V, F&gt;) =&gt; boolean)</span> | | The callback that generates a filtering function for a given filter item and column.<br />This function can return `null` to skip filtering for this item and column. |
20+
| <span class="prop-name optional">getValueAsString<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">(value: GridFilterItem['value']) =&gt; string</span> | | Converts the value of a filter item to a human-readable form. |
2021
| <span class="prop-name optional">InputComponent<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">React.JSXElementConstructor&lt;any&gt;</span> | | The input component to render in the filter panel for this filter operator. |
2122
| <span class="prop-name optional">InputComponentProps<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">Record&lt;string, any&gt;</span> | | The props to pass to the input component in the filter panel for this filter operator. |
2223
| <span class="prop-name optional">label<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">string</span> | | The label of the filter operator. |

packages/grid/x-data-grid/src/components/toolbar/GridToolbarFilterButton.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ const GridToolbarFilterButton = React.forwardRef<HTMLButtonElement, GridToolbarF
7777
.getLocaleText(`filterOperator${capitalize(item.operator!)}` as GridTranslationKeys)!
7878
.toString();
7979

80+
const getFilterItemValue = (item: GridFilterItem): string => {
81+
const { getValueAsString } = lookup[item.field!].filterOperators!.find(
82+
(operator) => operator.value === item.operator,
83+
)!;
84+
85+
return getValueAsString ? getValueAsString(item.value) : item.value;
86+
};
87+
8088
return (
8189
<div>
8290
{apiRef.current.getLocaleText('toolbarFiltersTooltipActive')(activeFilters.length)}
@@ -86,7 +94,7 @@ const GridToolbarFilterButton = React.forwardRef<HTMLButtonElement, GridToolbarF
8694
<li key={index}>
8795
{`${lookup[item.field!].headerName || item.field}
8896
${getOperatorLabel(item)}
89-
${item.value ?? ''}`}
97+
${item.value ? getFilterItemValue(item) : ''}`}
9098
</li>
9199
)),
92100
}))}

packages/grid/x-data-grid/src/models/gridFilterOperator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ export interface GridFilterOperator<R extends GridValidRowModel = any, V = any,
3636
* The props to pass to the input component in the filter panel for this filter operator.
3737
*/
3838
InputComponentProps?: Record<string, any>;
39+
/**
40+
* Converts the value of a filter item to a human-readable form.
41+
* @param {GridFilterItem['value']} value The filter item value.
42+
* @returns {string} The value formatted to be displayed in the UI of filter button tooltip.
43+
*/
44+
getValueAsString?: (value: GridFilterItem['value']) => string;
3945
/**
4046
* If `false`, filter operator doesn't require user-entered value to work.
4147
* Usually should be set to `false` for filter operators that don't have `InputComponent` (for example `isEmpty`)

packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { expect } from 'chai';
55
import {
66
DataGrid,
77
DataGridProps,
8+
GridToolbarFilterButton,
89
GridColDef,
910
GridFilterItem,
1011
GridPreferencePanelsValue,
@@ -1105,6 +1106,68 @@ describe('<DataGrid /> - Filter', () => {
11051106
});
11061107
});
11071108

1109+
describe('custom `filterOperators`', () => {
1110+
it('should allow to cutomize filter tooltip using `filterOperator.getValueAsString`', () => {
1111+
render(
1112+
<div style={{ width: '100%', height: '400px' }}>
1113+
<DataGrid
1114+
filterModel={{
1115+
items: [{ field: 'name', operator: 'contains', value: 'John' }],
1116+
}}
1117+
rows={[
1118+
{
1119+
id: 0,
1120+
name: 'John Doe',
1121+
},
1122+
{
1123+
id: 1,
1124+
name: 'Mike Smith',
1125+
},
1126+
]}
1127+
columns={[
1128+
{
1129+
field: 'name',
1130+
type: 'string',
1131+
filterOperators: [
1132+
{
1133+
label: 'Contains',
1134+
value: 'contains',
1135+
getApplyFilterFn: (filterItem) => {
1136+
return (params) => {
1137+
if (
1138+
!filterItem.field ||
1139+
!filterItem.value ||
1140+
!filterItem.operator ||
1141+
!params.value
1142+
) {
1143+
return null;
1144+
}
1145+
return params.value.includes(filterItem.value);
1146+
};
1147+
},
1148+
getValueAsString: (value) => `"${value}" text string`,
1149+
},
1150+
],
1151+
},
1152+
]}
1153+
components={{ Toolbar: GridToolbarFilterButton }}
1154+
/>
1155+
</div>,
1156+
);
1157+
1158+
const filterButton = document.querySelector('button[aria-label="Show filters"]');
1159+
expect(screen.queryByRole('tooltip')).to.equal(null);
1160+
1161+
fireEvent.mouseOver(filterButton);
1162+
clock.tick(1000); // tooltip display delay
1163+
1164+
const tooltip = screen.getByRole('tooltip');
1165+
1166+
expect(tooltip).toBeVisible();
1167+
expect(tooltip.textContent).to.contain('"John" text string');
1168+
});
1169+
});
1170+
11081171
it('should translate operators dynamically in toolbar without crashing ', () => {
11091172
expect(() => {
11101173
return (

0 commit comments

Comments
 (0)