Reputation: 639
How can I in mui/DataGrid custoim filter set value which will be seen in onFilterModelChange
?
I have code:
function MyFilterPanel() {
const apiRef = useGridApiContext();
const handleDateChange = () => {
const { state, setState, forceUpdate } = apiRef.current;
setState({
filterModel: {
items: [{ columnField: 'quantity', operatorValue: '>', value: 10000 }],
},
});
};
return (
<DateRangePicker
onChange={handleDateChange}
/>
);
}
// and
<DataGrid
...
filterMode="server"
onFilterModelChange={(newValue) => {
console.log(newValue);
}}
components={{
FilterPanel: MyFilterPanel,
}}
/>
I have got error:
TypeError: Cannot read properties of undefined (reading 'columnVisibilityModel')
EDIT. I added my code to show how I want to use it. https://codesandbox.io/s/datagrid-forked-2ulvnu
How to use that:
...
import * as React from "react";
import DateRangePicker from "rsuite/DateRangePicker";
import { DataGrid, useGridApiContext } from "@mui/x-data-grid";
import "./ui.css"; // @import "rsuite/dist/rsuite.css";
function DateRangePickerFilterPanel() {
const apiRef = useGridApiContext();
const handleDateChange = (value) => {
// I want set here values for previous and next date
};
return <DateRangePicker onChange={handleDateChange} />;
}
const rows = [
{ id: "2020-01-02", col1: "Hello" },
{ id: "2020-01-03", col1: "MUI X" },
{ id: "2020-01-04", col1: "Material UI" },
{ id: "2020-01-05", col1: "MUI" },
{ id: "2020-01-06", col1: "Joy UI" },
{ id: "2020-01-07", col1: "MUI Base" }
];
const columns = [
{ field: "id", headerName: "DateTime", type: "dateTime", width: 150 },
{ field: "col1", headerName: "Column 1", width: 150 }
];
export default function App() {
const [dates, setDates] = React.useState({});
/*
const getAllNames = () => {
axiosInstance.get(`${API_PATH}/api/names?startDate=${dates.startDate}&endDate=${dates.endDate}`)
.then((response) => {
...
})
.catch((error) => console.error(`Error: ${error}`));
};
*/
return (
<div style={{ height: 300, width: "100%" }}>
<DataGrid
rows={rows}
pagination
columns={columns}
paginationMode="server"
rowsPerPageOptions={[10]}
filterMode="server"
onFilterModelChange={(newValue) => {
// And here I want to get that data to be able
// to pas it to backend request or somehow have acces
// to it in fucntion App()
console.log(newValue);
// setDates({
// startDate: newValue[0],
// endDate: newValue[1].toISOString()
// });
}}
components={{
FilterPanel: DateRangePickerFilterPanel
}}
/>
</div>
);
}
Upvotes: 3
Views: 11016
Reputation: 830
UPDATE: Given the clarification from OP that they are NOT using MUI DataGridPro and are using server-side filtering, here is a solution:
If I understand you correctly, it looks like you are trying to accomplish the following:
For #1, we can capture the date values OUTSIDE of the DateRangePickerFilterPanel by passing the onChange handler function in as a prop. You can use a custom filter panel and pass it the handler function as a prop using the components and componentsProps attributes of DataGrid.
function DateRangePickerFilterPanel(props) {
// Instead of handling a date change here, pass the handler in as a prop.
// This allows you access to the selected values in App. You could also use
// a state management library like redux, but that is not shown here.
return <DateRangePicker onChange={props.onChange} />;
}
export default function App() {
const [dates, setDates] = useState()
const handleDateChange = (newValue) => {
// update local state with the new values
setDates(newValue);
}
return (
<DataGrid
rows={rows} // defined elsewhere
columns={columns} // defined elsewhere
components={{
FilterPanel: DateRangePickerFilterPanel,
}}
componentsProps={{
filterPanel: { onChange: handleDateChange }
}}
>
</DataGrid>
);
}
Second, we want to call the server whenever the filter dates are updated. We are storing the ‘dates’ in react state and we can use a useEffect hook to call the server every time those dates are updated
export default function App() {
const [dates, setDates] = useState()
useEffect( () => {
// call the server here
}, [dates]);
}
NOTE: the server-side documentation here indicates that you need to use the onFilterModelChange handler, but that is not necessary in this case since you are using a custom filter panel. We can trigger off of the update of the DateRangePicker and we do not need to use the onFilterModelChange.
Here is the full solution with comments:
import * as React from "react";
import { DateRangePicker } from "rsuite";
import { DataGrid, GridFilterModel } from "@mui/x-data-grid";
import "./ui.css";
import { fakeAxios } from "./server";
function DateRangePickerFilterPanel(props) {
// Instead of handling a date change here, pass the handler in as a prop.
// This allows you access to the selected values in App. You could also use
// a state management library like redux, but that is not shown here.
return <DateRangePicker onChange={props.onChange} />;
}
const columns = [
{ field: "id", headerName: "ID", width: 150 },
{ field: "created", headerName: "DateTime", type: "date", width: 150 },
{ field: "col1", headerName: "Column 1", width: 150 }
];
export default function App() {
// These are the selected values in the date range picker. To use server
// side filtering they must be sent to the server, and the server returns
// the filtered dataset.
const [dates, setDates] = React.useState({});
// Store the row data for the data table in react state. This will be updated
// when you call the server API with filter parameters.
const [rows, setRows] = React.useState([]);
// Here is where we handle the date change in the filter panel. Set the dates
// state so it can be used by the server API.
const handleDateChange = (newValue) => {
setDates(newValue);
};
// The rows for the datatable are loaded from the server using the dates as
// a filter. This useEffect runs (and calls the server) every time the value
// of 'dates' changes.
React.useEffect(() => {
fakeAxios
.get(`/api/names?startDate=${dates[0]}&endDate=${dates[1]}`)
.then((response) => {
console.log(
`server called with filter; returned ${response.length} records`
);
setRows(response);
});
}, [dates]);
return (
<div style={{ height: 500, width: "100%" }}>
<DataGrid
rows={rows}
pagination
columns={columns}
paginationMode="server"
rowCount={10}
rowsPerPageOptions={[10, 100]}
filterMode="server"
// onFilterModelChange is not needed since we are using a custom filter
// panel.
components={{
FilterPanel: DateRangePickerFilterPanel
}}
componentsProps={{
filterPanel: { onChange: handleDateChange }
}}
/>
</div>
);
}
I am mocking the server response with the 'fakeAxios' object. It does not filter the data as it would in the actual server and instead just returns a random number of records.
See the full code sandbox for more detail here: https://codesandbox.io/s/datagrid-forked-version2-koz9cy?file=/src/App.tsx
Original Answer:
tl;dr
The main issue here is that GridApi is a pro/premium feature that will work on DataGridPro, but not DataGrid. The documentation isn't super clear about this (by their own admission here: https://github.com/mui/mui-x/issues/2904#issuecomment-945436602). In the API docs for DataGrid the apiRef
property is not available, but it is there on DataGridPro.
The 2nd issue is that you should be using useGridApiRef() not useGridApiContext(). Basically, useGridApiRef() is for accessing the GridApi from outside the data grid, while useGridApiContext() is used to access the GRidApi from within the data grid (they provide a detailed explanation here)
Here is the code that accomplishes what you are looking for:
import { useState } from "react";
import { DataGridPro, useGridApiRef } from "@mui/x-data-grid-pro";
import { DateRangePicker, LocalizationProvider } from "@mui/x-date-pickers-pro";
import Box from "@mui/material/Box";
import TextField from "@mui/material/TextField";
import { AdapterDayjs } from "@mui/x-date-pickers-pro/AdapterDayjs";
import "./styles.css";
export default function App() {
const [value, setValue] = useState([null, null]);
const gridApi = useGridApiRef();
const rows = [
{ id: 1, col1: "Hello", col2: "World", quantity: 5000 },
{ id: 2, col1: "DataGridPro", col2: "is Awesome", quantity: 5000 },
{ id: 3, col1: "MUI", col2: "is Amazing", quantity: 12000 }
];
const columns = [
{ field: "col1", headerName: "Column 1", width: 150 },
{ field: "col2", headerName: "Column 2", width: 150 },
{ field: "quantity", headerName: "Quantity", width: 150, type: "number" }
];
const handleDateChange = (newValue) => {
setValue(newValue);
if (gridApi.current) {
gridApi.current.setFilterModel({
items: [
{
columnField: "quantity",
operatorValue: ">",
value: "10000"
}
]
});
}
};
return (
<div className="App" style={{ height: "300px" }}>
<h1>Hello CodeSandbox</h1>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DateRangePicker
value={value}
onChange={handleDateChange}
renderInput={(startProps, endProps) => (
<>
<TextField {...startProps} />
<Box sx={{ mx: 2 }}> to </Box>
<TextField {...endProps} />
</>
)}
></DateRangePicker>
</LocalizationProvider>
<DataGridPro
apiRef={gridApi}
rows={rows}
columns={columns}
onFilterModelChange={(newValue) => {
console.log(`received filter mode change: ${newValue}`);
console.log(newValue);
}}
></DataGridPro>
</div>
);
}
Code Sandbox here: https://codesandbox.io/s/stackoverflow-mui-datagrid-ehxesp
Upvotes: 5
Reputation: 2888
I am assuming that you want to get the dates from the DateRangePicker
and pass them to your API call. Once user selects the dateRange then again re-populate the datagrid(assuming based on filterMode
set to server
). I have updated your code. please check. As you are not using Mui's FilterModel
you don't need onFilterModelChange
prop.
import DateRangePicker from "rsuite/DateRangePicker";
import { DataGrid} from "@mui/x-data-grid";
import "./ui.css";
const getAllNames = (startDate, endDate)=> {
console.log(startDate, endDate);
// Add your API call here
};
function DateRangePickerFilterPanel() {
const handleDateChange = (value) => {
getAllNames(value[0], value[1]);
};
return <DateRangePicker onChange={handleDateChange} />;
};
const rows = [
{ id: "2020-01-02", col1: "Hello" },
{ id: "2020-01-03", col1: "MUI X" },
{ id: "2020-01-04", col1: "Material UI" },
{ id: "2020-01-05", col1: "MUI" },
{ id: "2020-01-06", col1: "Joy UI" },
{ id: "2020-01-07", col1: "MUI Base" }
];
const columns = [
{ field: "id", headerName: "DateTime", type: "dateTime", width: 150 },
{ field: "col1", headerName: "Column 1", width: 150 }
];
export default function App() {
/*
const getAllNames = () => {
axiosInstance.get(`${API_PATH}/api/names?startDate=${dates.startDate}&endDate=${dates.endDate}`)
.then((response) => {
...
})
.catch((error) => console.error(`Error: ${error}`));
};
*/
return (
<div style={{ height: 300, width: "100%" }}>
<DataGrid
rows={rows}
pagination
columns={columns}
paginationMode="server"
rowsPerPageOptions={[10]}
filterMode="server"
components={{
FilterPanel: DateRangePickerFilterPanel
}}
/>
</div>
);
}
Upvotes: -1