diff --git a/docs/data/data-grid/filtering-recipes/FilteredRowCount.js b/docs/data/data-grid/filtering-recipes/FilteredRowCount.js
new file mode 100644
index 000000000000..7f517d35cd22
--- /dev/null
+++ b/docs/data/data-grid/filtering-recipes/FilteredRowCount.js
@@ -0,0 +1,88 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import { DataGridPro, useGridApiRef } from '@mui/x-data-grid-pro';
+import { useDemoData } from '@mui/x-data-grid-generator';
+import Button from '@mui/material/Button';
+import Stack from '@mui/material/Stack';
+
+const predefinedFilters = [
+ {
+ label: 'All',
+ filterModel: { items: [] },
+ },
+ {
+ label: 'Filled',
+ filterModel: { items: [{ field: 'status', operator: 'is', value: 'Filled' }] },
+ },
+ {
+ label: 'Open',
+ filterModel: { items: [{ field: 'status', operator: 'is', value: 'Open' }] },
+ },
+ {
+ label: 'Rejected',
+ filterModel: { items: [{ field: 'status', operator: 'is', value: 'Rejected' }] },
+ },
+ {
+ label: 'Partially Filled',
+ filterModel: {
+ items: [{ field: 'status', operator: 'is', value: 'PartiallyFilled' }],
+ },
+ },
+];
+
+export default function FilteredRowCount() {
+ const { data } = useDemoData({
+ dataSet: 'Commodity',
+ rowLength: 1000,
+ maxColumns: 10,
+ });
+
+ const apiRef = useGridApiRef();
+
+ const [predefinedFiltersRowCount, setPredefinedFiltersRowCount] = React.useState(
+ [],
+ );
+
+ const getFilteredRowsCount = React.useCallback(
+ (filterModel) => {
+ const { filteredRowsLookup } = apiRef.current.getFilterState(filterModel);
+ return Object.keys(filteredRowsLookup).filter(
+ (rowId) => filteredRowsLookup[rowId] === true,
+ ).length;
+ },
+ [apiRef],
+ );
+
+ React.useEffect(() => {
+ // Calculate the row count for predefined filters
+ if (data.rows.length === 0) {
+ return;
+ }
+
+ setPredefinedFiltersRowCount(
+ predefinedFilters.map(({ filterModel }) => getFilteredRowsCount(filterModel)),
+ );
+ }, [apiRef, data.rows, getFilteredRowsCount]);
+
+ return (
+
+
+ {predefinedFilters.map(({ label, filterModel }, index) => {
+ const count = predefinedFiltersRowCount[index];
+ return (
+
+ );
+ })}
+
+
+
+
+
+ );
+}
diff --git a/docs/data/data-grid/filtering-recipes/FilteredRowCount.tsx b/docs/data/data-grid/filtering-recipes/FilteredRowCount.tsx
new file mode 100644
index 000000000000..df925c75a800
--- /dev/null
+++ b/docs/data/data-grid/filtering-recipes/FilteredRowCount.tsx
@@ -0,0 +1,88 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import { DataGridPro, useGridApiRef, GridFilterModel } from '@mui/x-data-grid-pro';
+import { useDemoData } from '@mui/x-data-grid-generator';
+import Button from '@mui/material/Button';
+import Stack from '@mui/material/Stack';
+
+const predefinedFilters: { label: string; filterModel: GridFilterModel }[] = [
+ {
+ label: 'All',
+ filterModel: { items: [] },
+ },
+ {
+ label: 'Filled',
+ filterModel: { items: [{ field: 'status', operator: 'is', value: 'Filled' }] },
+ },
+ {
+ label: 'Open',
+ filterModel: { items: [{ field: 'status', operator: 'is', value: 'Open' }] },
+ },
+ {
+ label: 'Rejected',
+ filterModel: { items: [{ field: 'status', operator: 'is', value: 'Rejected' }] },
+ },
+ {
+ label: 'Partially Filled',
+ filterModel: {
+ items: [{ field: 'status', operator: 'is', value: 'PartiallyFilled' }],
+ },
+ },
+];
+
+export default function FilteredRowCount() {
+ const { data } = useDemoData({
+ dataSet: 'Commodity',
+ rowLength: 1000,
+ maxColumns: 10,
+ });
+
+ const apiRef = useGridApiRef();
+
+ const [predefinedFiltersRowCount, setPredefinedFiltersRowCount] = React.useState<
+ number[]
+ >([]);
+
+ const getFilteredRowsCount = React.useCallback(
+ (filterModel: GridFilterModel) => {
+ const { filteredRowsLookup } = apiRef.current.getFilterState(filterModel);
+ return Object.keys(filteredRowsLookup).filter(
+ (rowId) => filteredRowsLookup[rowId] === true,
+ ).length;
+ },
+ [apiRef],
+ );
+
+ React.useEffect(() => {
+ // Calculate the row count for predefined filters
+ if (data.rows.length === 0) {
+ return;
+ }
+
+ setPredefinedFiltersRowCount(
+ predefinedFilters.map(({ filterModel }) => getFilteredRowsCount(filterModel)),
+ );
+ }, [apiRef, data.rows, getFilteredRowsCount]);
+
+ return (
+
+
+ {predefinedFilters.map(({ label, filterModel }, index) => {
+ const count = predefinedFiltersRowCount[index];
+ return (
+
+ );
+ })}
+
+
+
+
+
+ );
+}
diff --git a/docs/data/data-grid/filtering-recipes/filtering-recipes.md b/docs/data/data-grid/filtering-recipes/filtering-recipes.md
index 6f2f60c5c4d1..fa5322aa7f22 100644
--- a/docs/data/data-grid/filtering-recipes/filtering-recipes.md
+++ b/docs/data/data-grid/filtering-recipes/filtering-recipes.md
@@ -15,3 +15,9 @@ This requires certain considerations due to the Grid's context structure.
The following example shows how to accomplish this:
{{"demo": "QuickFilterOutsideOfGrid.js", "bg": "inline", "defaultCodeOpen": false}}
+
+## Calculating filtered rows in advance
+
+The [Grid API](/x/react-data-grid/api-object/#how-to-use-the-api-object) provides the [`getFilterState`](/x/api/data-grid/grid-api/#grid-api-prop-getFilterState) method, which allows you to display the row count for predefined filters upfront without applying filters to the Data Grid:
+
+{{"demo": "FilteredRowCount.js", "bg": "inline", "defaultCodeOpen": false}}
diff --git a/docs/pages/x/api/data-grid/grid-api.json b/docs/pages/x/api/data-grid/grid-api.json
index a4fc87914cd1..88b2080043cd 100644
--- a/docs/pages/x/api/data-grid/grid-api.json
+++ b/docs/pages/x/api/data-grid/grid-api.json
@@ -116,6 +116,12 @@
"required": true,
"isProPlan": true
},
+ "getFilterState": {
+ "type": {
+ "description": "(filterModel: GridFilterModel) => GridStateCommunity['filter']"
+ },
+ "required": true
+ },
"getLocaleText": {
"type": {
"description": "<T extends GridTranslationKeys>(key: T) => GridLocaleText[T]"
diff --git a/docs/pages/x/api/data-grid/grid-filter-api.json b/docs/pages/x/api/data-grid/grid-filter-api.json
index 626ae4fcb29e..48c344e8b190 100644
--- a/docs/pages/x/api/data-grid/grid-filter-api.json
+++ b/docs/pages/x/api/data-grid/grid-filter-api.json
@@ -7,6 +7,11 @@
"description": "Deletes a GridFilterItem.",
"type": "(item: GridFilterItem) => void"
},
+ {
+ "name": "getFilterState",
+ "description": "Returns the filter state for the given filter model without applying it to the data grid.",
+ "type": "(filterModel: GridFilterModel) => GridStateCommunity['filter']"
+ },
{ "name": "hideFilterPanel", "description": "Hides the filter panel.", "type": "() => void" },
{
"name": "ignoreDiacritics",
diff --git a/docs/translations/api-docs/data-grid/grid-api.json b/docs/translations/api-docs/data-grid/grid-api.json
index 02e89d3757ea..cec2f0cfce03 100644
--- a/docs/translations/api-docs/data-grid/grid-api.json
+++ b/docs/translations/api-docs/data-grid/grid-api.json
@@ -66,6 +66,9 @@
"description": "Returns the grid data as an exceljs workbook.
This method is used internally by exportDataAsExcel
."
},
"getExpandedDetailPanels": { "description": "Returns the rows whose detail panel is open." },
+ "getFilterState": {
+ "description": "Returns the filter state for the given filter model without applying it to the data grid."
+ },
"getLocaleText": { "description": "Returns the translation for the key
." },
"getPinnedColumns": { "description": "Returns which columns are pinned." },
"getRootDimensions": { "description": "Returns the dimensions of the grid" },
diff --git a/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx b/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx
index 27b90dfb2317..031320af23c3 100644
--- a/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx
+++ b/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx
@@ -107,21 +107,13 @@ export const useGridFilter = (
const updateFilteredRows = React.useCallback(() => {
apiRef.current.setState((state) => {
const filterModel = gridFilterModelSelector(state, apiRef.current.instanceId);
- const isRowMatchingFilters =
- props.filterMode === 'client'
- ? buildAggregatedFilterApplier(filterModel, apiRef, props.disableEval)
- : null;
-
- const filteringResult = apiRef.current.applyStrategyProcessor('filtering', {
- isRowMatchingFilters,
- filterModel: filterModel ?? getDefaultGridFilterModel(),
- });
+ const filterState = apiRef.current.getFilterState(filterModel);
const newState = {
...state,
filter: {
...state.filter,
- ...filteringResult,
+ ...filterState,
},
};
@@ -133,7 +125,7 @@ export const useGridFilter = (
};
});
apiRef.current.publishEvent('filteredRowsSet');
- }, [apiRef, props.filterMode, props.disableEval]);
+ }, [apiRef]);
const addColumnMenuItem = React.useCallback>(
(columnMenuItems, colDef) => {
@@ -321,6 +313,30 @@ export const useGridFilter = (
[apiRef, logger, props.disableMultipleColumnsFiltering],
);
+ const getFilterState = React.useCallback(
+ (inputFilterModel) => {
+ const filterModel = sanitizeFilterModel(
+ inputFilterModel,
+ props.disableMultipleColumnsFiltering,
+ apiRef,
+ );
+ const isRowMatchingFilters =
+ props.filterMode === 'client'
+ ? buildAggregatedFilterApplier(filterModel, apiRef, props.disableEval)
+ : null;
+
+ const filterResult = apiRef.current.applyStrategyProcessor('filtering', {
+ isRowMatchingFilters,
+ filterModel: filterModel ?? getDefaultGridFilterModel(),
+ });
+ return {
+ ...filterResult,
+ filterModel,
+ };
+ },
+ [props.disableMultipleColumnsFiltering, props.filterMode, props.disableEval, apiRef],
+ );
+
const filterApi: GridFilterApi = {
setFilterLogicOperator,
unstable_applyFilters: applyFilters,
@@ -332,6 +348,7 @@ export const useGridFilter = (
hideFilterPanel,
setQuickFilterValues,
ignoreDiacritics: props.ignoreDiacritics,
+ getFilterState,
};
useGridApiMethod(apiRef, filterApi, 'public');
diff --git a/packages/x-data-grid/src/models/api/gridFilterApi.ts b/packages/x-data-grid/src/models/api/gridFilterApi.ts
index d1c3ceadadc3..d86aabc67fb2 100644
--- a/packages/x-data-grid/src/models/api/gridFilterApi.ts
+++ b/packages/x-data-grid/src/models/api/gridFilterApi.ts
@@ -2,6 +2,7 @@ import { GridFilterModel } from '../gridFilterModel';
import { GridFilterItem, GridLogicOperator } from '../gridFilterItem';
import { GridControlledStateReasonLookup } from '../events';
import type { DataGridProcessedProps } from '../props/DataGridProps';
+import { GridStateCommunity } from '../gridStateCommunity';
/**
* The filter API interface that is available in the grid [[apiRef]].
@@ -61,4 +62,10 @@ export interface GridFilterApi {
* Returns the value of the `ignoreDiacritics` prop.
*/
ignoreDiacritics: DataGridProcessedProps['ignoreDiacritics'];
+ /**
+ * Returns the filter state for the given filter model without applying it to the data grid.
+ * @param {GridFilterModel} filterModel The filter model to get the state for.
+ * @returns {GridStateCommunity['filter']} The filter state.
+ */
+ getFilterState: (filterModel: GridFilterModel) => GridStateCommunity['filter'];
}