Reputation: 73
In the MUI DataGrid, by clicking the options menu on any header column, you can access the column visibility panel.
But I haven't found a way to display this panel from outside the Grid. The idea was to have a button that, when clicked, could display the panel. Even if it remains with its position inside the Grid
This would avoid having to build a component for this purpose.
Upvotes: 7
Views: 2463
Reputation: 42208
This section of the grid is called the GridPreferencesPanel
. You can open it imperatively by using the showPreferences
function on the grid API. Here is the documentation from the MUI source code:
/**
* The preferences panel API interface that is available in the grid [[apiRef]].
*/
export interface GridPreferencesPanelApi {
/**
* Displays the preferences panel. The `newValue` argument controls the content of the panel.
* @param {GridPreferencePanelsValue} newValue The panel to open. Use `"filters"` or `"columns"`.
*/
showPreferences: (newValue: GridPreferencePanelsValue) => void;
/**
* Hides the preferences panel.
*/
hidePreferences: () => void;
}
The same function is used for opening the filters menu and the columns menu so you will need to pass the correct argument to determine which to show. Your example image depicts the columns menu. If you are using TypeScript, you should import the GridPreferencePanelsValue
enum and call showPreferences(GridPreferencePanelsValue.columns)
. With plain JavaScript you can call showPreferences("columns")
.
To do this inside of the grid context, for example in a custom Toobar
component, you will use the useGridApiContext
hook to access the function.
import * as React from "react";
import { Button } from "@mui/material";
import {
GridToolbarContainer,
GridPreferencePanelsValue,
useGridApiContext
} from "@mui/x-data-grid";
export const CustomToolbar = () => {
const apiRef = useGridApiContext();
const handleClick = () => {
apiRef.current?.showPreferences(GridPreferencePanelsValue.columns);
};
return (
<GridToolbarContainer>
<Button onClick={handleClick}>Show Columns</Button>
</GridToolbarContainer>
);
};
<DataGrid
components={{
Toolbar: CustomToolbar
}}
// your other props
/>
In order to place your button outside of the grid itself, you need to use the useGridApiRef
hook (Pro-only feature). This creates a ref which you will pass to the DataGrid
but also allows you to use that ref in your parent component.
import * as React from "react";
import { Box, Button } from "@mui/material";
import {
DataGridPro,
GridPreferencePanelsValue,
useGridApiRef
} from "@mui/x-data-grid-pro";
export const ParentComponent = () => {
const apiRef = useGridApiRef();
const handleClick = () => {
apiRef.current?.showPreferences(GridPreferencePanelsValue.columns);
};
return (
<Box>
<Button onClick={handleClick}>Show Columns</Button>
<Box sx={{ height: 400, width: "100%" }}>
<DataGridPro
apiRef={apiRef}
// your other props
/>
</Box>
</Box>
);
}
There are certainly some workarounds which can avoid the use of the pro-only hook, but this is the cleanest way.
Upvotes: 8
Reputation: 632
I'm not sure if I missed it in the docs, but it doesn't look like you can control the visibility of the default MUI 'Column Visibility Panel' with the Grid API like you can with the Filter Panel.
However, you can provide your own columnVisibilityModel to the DataGrid which will dictate which columns are visible in the grid. This will let you control the visibility of each column from outside the grid, but you will have to create your own Column Visibility Panel.
Here is a code sandbox example: https://codesandbox.io/s/mui-5-forked-zj4glu?file=/src/ArrowPopper.tsx
Code:
import * as React from "react";
import { Box, Button, FormControlLabel, Popper, Switch } from "@mui/material";
import { DataGrid, GridColDef, GridValueGetterParams } from "@mui/x-data-grid";
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", width: 90 },
{
field: "firstName",
headerName: "First name",
width: 150,
editable: true
},
{
field: "lastName",
headerName: "Last name",
width: 150,
editable: true
},
{
field: "age",
headerName: "Age",
type: "number",
width: 110,
editable: true
},
{
field: "fullName",
headerName: "Full name",
description: "This column has a value getter and is not sortable.",
sortable: false,
width: 160,
valueGetter: (params: GridValueGetterParams) =>
`${params.row.firstName || ""} ${params.row.lastName || ""}`
}
];
const rows = [
{ id: 1, lastName: "Snow", firstName: "Jon", age: 35 },
{ id: 2, lastName: "Lannister", firstName: "Cersei", age: 42 },
{ id: 3, lastName: "Lannister", firstName: "Jaime", age: 45 },
{ id: 4, lastName: "Stark", firstName: "Arya", age: 16 },
{ id: 5, lastName: "Targaryen", firstName: "Daenerys", age: null },
{ id: 6, lastName: "Melisandre", firstName: null, age: 150 },
{ id: 7, lastName: "Clifford", firstName: "Ferrara", age: 44 },
{ id: 8, lastName: "Frances", firstName: "Rossini", age: 36 },
{ id: 9, lastName: "Roxie", firstName: "Harvey", age: 65 }
];
export default function DataGridDemo() {
const [columnVisibility, setColumnVisibility] = React.useState({
id: true,
firstName: true,
lastName: true,
age: true,
fullName: true
});
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const toggleColumnVisibility = (e) => {
setColumnVisibility((prev) => ({
...prev,
[e.target.name]: e.target.checked
}));
};
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(anchorEl ? null : event.currentTarget);
};
const open = Boolean(anchorEl);
return (
<Box sx={{ height: 400, width: "100%" }}>
<Button
onClick={handleClick}
variant="contained"
sx={{
mb: 2
}}
>
Show Column Visibility
</Button>
<DataGrid
rows={rows}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
checkboxSelection
disableSelectionOnClick
columnVisibilityModel={columnVisibility}
/>
<Popper open={open} anchorEl={anchorEl}>
<Box
sx={{
display: "flex",
flexDirection: "column",
backgroundColor: "white"
}}
>
{columns.map((c) => (
<FormControlLabel
key={c.field}
label={c.headerName}
control={
<Switch
name={c.field}
checked={columnVisibility[c.field]}
onChange={toggleColumnVisibility}
/>
}
/>
))}
</Box>
</Popper>
</Box>
);
}
Upvotes: 1