Let's say I have a datagrid table like so (from the official MUI documentation):
import * as React from 'react';
import { DataGrid, GridToolbar } from '@mui/x-data-grid';
import { useDemoData } from '@mui/x-data-grid-generator';
const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin'];
export default function ControlledFilters() {
const { data } = useDemoData({
dataSet: 'Employee',
visibleFields: VISIBLE_FIELDS,
rowLength: 100,
});
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
{...data}
components={{
Toolbar: GridToolbar,
}}
/>
</div>
);
}
Now let's say I wanted to filter the column 'name' in this table by onClick of a button. That button, when clicked, should give a string, let's say 'Ray'. When this button is clicked, I want to automatically filter the table so that every value in the 'name' column that contains the string 'Ray' only gets displayed.
My Approach so far
I have tried using useState from react and the filterModel prop in DataGrid so that pressing the button filters the table like so:
....
const [filt, setFilt] = useState('') // Initialize it with an empty filter
const handleClick = () => {
setFilt('Ray');
};
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
{...data}
components={{
Toolbar: GridToolbar,
}}
filterModel={{
items: [{ columnField: 'name', operatorValue: 'contains', value: filt },
]
}}
/>
<Button onClick={handleClick}>Change Filter</Button>
</div>
);
}
This works but the problem with this approach is that it locks every other filter and the filter is basically stuck on the 'name' column and the user can now only use the button to filter the column. It doesn't even let me remove the filter.
I have also tried the onFilterModelChange prop but it didn't work; I am honestly confused on how to use it for this specific case. Any help would be appreciated.
You were close. I believe that you would need to form the entire items array instead of only a part of the filter object.
i.e. setFilt[{ columnField: 'name', operatorValue: 'contains', value: "Ray"}] instead of setFilt("Ray") along with { columnField: 'name', operatorValue: 'contains', value: filt}
You can reset the filters by setting items: [] in the filterModel.
CodeSandbox Example with a single filter criterion.
(I had to install @mui/material v5.9.2 instead of v5.9.3 to get it to work if you have any compile issues on codesandbox)
const [filt, setFilt] = useState([])
<DataGrid
{...data}
filterModel={{
items: filt
}}
/>
<Button
onClick={() =>
setFilt([
{
columnField: "name",
operatorValue: "startsWith",
value: "A"
}
])
}
>
Name Starts With A
</Button>
<Button
onClick={() => setFilt([])}
>
Reset Filters
</Button>
CodeSandbox Example of a multi-filter grid with buttons.
Multi-filtering is only possible with the Pro version of MUI. Without the Pro version, any additional filters added past the first one are ignored (as you discovered).
This is what I came up with using @mui/x-data-grid-pro and 3 different buttons that each apply a unique filter:
const [filt, setFilt] = useState([])
<DataGridPro
{...data}
filterModel={{
items: filt,
GridLinkOperator: GridLinkOperator.And
}}
/>
<Button
onClick={() =>
setFilt([
...filt,
{
id: 1,
columnField: "rating",
operatorValue: ">",
value: 3
}
])
}
>
Rating Greater Than 3
</Button>
<Button
onClick={() =>
setFilt([
...filt,
{
id: 2,
columnField: "name",
operatorValue: "startsWith",
value: "A"
}
])
}
>
Name Starts With A
</Button>
<Button
onClick={() => setFilt([])}
>
Reset Filters
</Button>
A caveat to be aware of --- you will need to add an id to each filter object in the items array when using multi-filtering.
e.g.
[
{ id: 1, columnField: 'rating', operatorValue: '>', value: 3 },
{ id: 2, columnField: 'name', operatorValue: 'startsWith', value: "A" }
]