mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.08k stars 1.26k forks source link

[data grid] The popover for the GridToolbarFilterButton and GridToolbarColumnsButton should open under their respective button. #13186

Closed mahammahmood closed 4 months ago

mahammahmood commented 4 months ago

The problem in depth

The popover for the GridToolbarFilterButton and GridToolbarColumnsButton should open under their respective button. For now both open at the start of the data grid. I'm using Data Grid Pro plan Version 7.

Screenshot 2024-05-20 180959 Screenshot 2024-05-20 180921 Below is an example of what I want. Screenshot 2024-05-20 181416

Your environment

`npx @mui/envinfo` ``` Don't forget to mention which browser you used. Output from `npx @mui/envinfo` goes here. ```

Search keywords: Data ,Grid , Pro, GridToolbarFilterButton, GridToolbarColumnsButton, version 7 Order ID: 81584

michelengelen commented 4 months ago

Hey @mahammahmood ... this is possible by anchoring the panel to the filter button instead of the toolbar. Here is an example from the docs: Customize the filter panel position

Here is the respective code example (with the columns button):

import * as React from 'react';
import {
  DataGrid,
  GridSlots, GridToolbarColumnsButton,
  GridToolbarContainer, GridToolbarExportContainer,
  GridToolbarFilterButton,
} from '@mui/x-data-grid';
import { useDemoData } from '@mui/x-data-grid-generator';

const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin'];

interface CustomToolbarProps {
  setFilterButtonEl: React.Dispatch<React.SetStateAction<HTMLButtonElement | null>>;
}

function CustomToolbar({ setFilterButtonEl }: CustomToolbarProps) {
  return (
    <GridToolbarContainer>
      <GridToolbarColumnsButton />
      <GridToolbarFilterButton ref={setFilterButtonEl} />
    </GridToolbarContainer>
  );
}

export default function CustomFilterPanelPosition() {
  const { data } = useDemoData({
    dataSet: 'Employee',
    visibleFields: VISIBLE_FIELDS,
    rowLength: 100,
  });

  const [filterButtonEl, setFilterButtonEl] =
    React.useState<HTMLButtonElement | null>(null);

  return (
    <div style={{ height: 400, width: '100%' }}>
      <DataGrid
        {...data}
        slots={{
          toolbar: CustomToolbar as GridSlots['toolbar'],
        }}
        slotProps={{
          panel: {
            anchorEl: filterButtonEl,
          },
          toolbar: {
            setFilterButtonEl,
          },
        }}
      />
    </div>
  );
}
Screenshot 2024-05-21 at 10 57 05
github-actions[bot] commented 4 months ago

:warning: This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue. Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

@mahammahmood: How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

mahammahmood commented 4 months ago

When i implement this solution i got error on this Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

this is my code. can you please help me to resolve this issue.

interface CustomToolbarProps {
  loadingState?: boolean;
  showCustomMenuButton?: boolean;
  RowSelectionModel?: boolean;
  setFilterButtonEl?: React.Dispatch<React.SetStateAction<HTMLButtonElement | null>>;
}

export const CustomToolbar: React.FC<CustomToolbarProps> = ({
     loadingState = true,
    showCustomMenuButton = false,
    RowSelectionModel = false,
    setFilterButtonEl,
})=> {
return (
<GridToolbarContainer>
    <GridToolbarColumnsButton />
     <GridToolbarFilterButton 
           ref={setFilterButtonEl} />
 </GridToolbarContainer>
  );
}
const Page = () => {
 const [filterButtonEl, setFilterButtonEl] = React.useState<HTMLButtonElement | null>(null);
  <DataGrid
            rows={locationRowsV2}
            columns={columns}
             slots={{
              toolbar: () => (
                <CustomToolbar
                   setFilterButtonEl={setFilterButtonEl}
                   filterButtonEl={filterButtonEl}
                  loadingState={loading}
                  RowSelectionModel={rowSelectionModel}
                  showCustomMenuButton={true}
             }}
           slotProps={{
              panel: {
                anchorEl: filterButtonEl,
              },
              columnsPanel: {
                sx: {
                  [`& .MuiDataGrid-columnsManagement > label:first-child, & .MuiDataGrid-columnsManagement > label:last-child`]:
                    {
                      display: '',
                    },
                },
              },
            }}
}