Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data grid] How to Avoid column readjustment #12929

Closed
Shudhanshu-Appnox opened this issue Apr 27, 2024 · 21 comments
Closed

[data grid] How to Avoid column readjustment #12929

Shudhanshu-Appnox opened this issue Apr 27, 2024 · 21 comments
Labels
component: data grid This is the name of the generic UI component, not the React module! support: commercial Support request from paid users support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/

Comments

@Shudhanshu-Appnox
Copy link

Shudhanshu-Appnox commented Apr 27, 2024

The problem in depth

Whenever the component rerenders the columns are Re-Adjusting can anyone hepl me on how to avoid this ?

Screen.Recording.2024-04-27.at.2.25.33.PM.mov

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
Order ID: 83077

@Shudhanshu-Appnox Shudhanshu-Appnox added status: waiting for maintainer These issues haven't been looked at yet by a maintainer support: commercial Support request from paid users labels Apr 27, 2024
@zannager zannager added component: data grid This is the name of the generic UI component, not the React module! support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/ labels Apr 29, 2024
@michelengelen
Copy link
Member

Please provide a minimal reproduction test case with the latest version. This would help a lot 👷.

A live example would be perfect. You can find a examples and guides on how to find templates in our docs with which you can provide examples for your specific use-case: Support - Bug reproduction.

Thank you! 🙇🏼

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 29, 2024
@michelengelen michelengelen changed the title How to Avoid column readjustment [data grid] How to Avoid column readjustment Apr 29, 2024
@Shudhanshu-Appnox
Copy link
Author

Hi @michelengelen to reproduce the bug I have to write down the whole code in the Codesplitz and It is over 2k - 3k line of code. Also this issue is currently we are facing in some of our Data Grid is there any better way I can share you the example.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 30, 2024
@Shudhanshu-Appnox
Copy link
Author

Can i share the our code implementation how we have defined the Columns for the data Grid will that help ?

@michelengelen
Copy link
Member

Hey @Shudhanshu-Appnox ... From your video it seems as if it happens when you click the columns button in the toolbar, is that correct?

Are you using a controlled column visibility approach?

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 30, 2024
@Shudhanshu-Appnox
Copy link
Author

@michelengelen
No, when the Component are mount the columns are collapsed into one another and after some time it gets to its original position.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 30, 2024
@michelengelen
Copy link
Member

OK, strange. Some questions:

  • Are you applying flex to the columns?
  • Is there any dynamic loading in place that would lead to a re-adjustment after some time?
  • If it is happening in multiple unrelated instances of the grid is there any adjustments you made recently to them?
  • Are you using a wrapped grid?
  • Are you using column autosizing?

If possible can you share the implementation in some way? That would make it a lot easier.

Thanks!

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 30, 2024
@Shudhanshu-Appnox
Copy link
Author

Shudhanshu-Appnox commented Apr 30, 2024

@michelengelen Here is the Column Configuration which we are using here

Column definitions
    const columns = useMemo<GridColDef[]>(
        () => [
            {
                ...GRID_CHECKBOX_SELECTION_COL_DEF,
                width: 30,
                maxWidth: 80,
                filterable: false,
                groupable: false,
                aggregable: false,
                pinnable: false,
                editable: true,
                isVisible: true,
                renderHeader: () => (
                    <div className="p-4">
                        <p className="text-sm text-[#475467] font-bold">Select</p>
                    </div>
                ),
                renderHeaderFilter: (params) => <ColumnCheckbox params={params} />,
            },
            {
                field: "activityTypeId",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Activity ID",
                // width: 200,
                minWidth: 100,
                isVisible: false,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: false,
                sortable: true,

            },
            {
                field: "activityCode",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Code",
                headerAlign: "center",
                // width: 200,
                minWidth: 100,
                isVisible: true,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: true,
                sortable: true,
                renderEditCell: (params) => (
                    <Box>
                        <GridEditTextFeild
                            params={params}
                            updateHandler={handleInlineUpdates}
                            min={GetValidationRule("activityCode")?.min}
                            max={GetValidationRule("activityCode")?.max}
                        />
                    </Box>
                ),
            },
            {
                field: "activityDescription",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Description",
                headerAlign: "center",
                // width: 200,
                minWidth: 200,
                isVisible: true,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: true,
                sortable: true,
                renderEditCell: (params) => (
                    <Box>
                        <GridEditTextFeild
                            params={params}
                            updateHandler={handleInlineUpdates}
                            min={GetValidationRule("activityDescription")?.min}
                            max={GetValidationRule("activityDescription")?.max}
                        />
                    </Box>
                ),
            },
            {
                field: "insUserId",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Ins UserId",
                // width: 200,
                minWidth: 100,
                isVisible: false,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: false,
                sortable: true,

            },
            {
                field: "insDateTime",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Ins DateTime",
                minWidth: 180,
                type: "date",
                isVisible: false,
                renderHeaderFilter: (params) => (
                    <ColumnFilterDateInput params={params} />
                ),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    const insDateTime = GetDateTime(value);
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={insDateTime}
                        />
                    );
                },
                valueGetter: (params) => new Date(params?.value),
                editable: false,
            },
            {
                field: "updUserId",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Upd UserId",
                minWidth: 100,
                isVisible: false,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: false,
                sortable: true,

            },
            {
                field: "updDateTime",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Upd DateTime",
                minWidth: 200,
                isVisible: false,
                type: "date",
                renderHeaderFilter: (params) => (
                    <ColumnFilterDateInput params={params} />
                ),
                valueGetter: (params) => {
                    if (params?.value) {
                        return new Date(params?.value)
                    } else {
                        return null
                    }
                },
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    if (value) {
                        const updDateTime = GetDateTime(value);
                        return (
                            <RenderTableCell
                                row={rowItem}
                                value={updDateTime}
                            />
                        );
                    } else {
                        return (
                            <RenderTableCell
                                row={rowItem}
                                value={"-"}
                            />
                        );
                    }
                },
                editable: false,
            },
            {
                field: "transactionId",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Transaction ID",
                // width: 200,
                minWidth: 100,
                isVisible: false,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: false,
                sortable: true,

            },
            {
                field: "insUser",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "INS User",
                // width: 200,
                minWidth: 100,
                isVisible: false,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: false,
                sortable: true,

            },
            {
                field: "updUser",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "UPD User",
                // width: 200,
                minWidth: 100,
                isVisible: false,
                renderHeaderFilter: (params) => (<ColumnFilerTextInput {...params} />),
                renderCell: (params) => {
                    const value = params?.value;
                    const rowItem = params?.row;
                    return (
                        <RenderTableCell
                            row={rowItem}
                            value={value}
                        />
                    );
                },
                editable: false,
                sortable: true,
            },
            {
                field: "recordStatus",
                flex: 1,
                groupable: false,
                aggregable: false,
                pinnable: false,
                headerName: "Status",
                headerAlign: "center",
                sortable: true,
                minWidth: 150,
                maxWidth: 150,
                isVisible: true,
                editable: true,
                type: "singleSelect",
                valueOptions: [
                    { key: "Active", value: "Active" },
                    { key: "Enabled", value: "Enabled" },
                    { key: "Disabled", value: "Disabled" },
                    { key: "Deleted", value: "Deleted" },
                    { key: "Undeleted", value: "Undeleted" },
                ],
                getOptionLabel: (option: any) => option?.key,
                renderHeaderFilter: (params: GridHeaderFilterCellProps) => {
                    return (
                        <ColumnHeaderFilter
                            params={params}
                            options={[
                                { key: "Active", value: "Active" },
                                { key: "Enabled", value: "Enabled" },
                                { key: "Disabled", value: "Disabled" },
                                { key: "Deleted", value: "Deleted" },
                                { key: "Undeleted", value: "Undeleted" },
                            ]}
                            filterLabel={"status"}
                        />
                    );
                },
                renderCell: (params) => {
                    const value = params?.value;
                    return (
                        <div className="flex justify-between items-center py-2 px-2">
                            <div
                                style={{
                                    backgroundColor:
                                        value === "Deleted" || value === "Disabled"
                                            ? "#FECDCA"
                                            : "#A6F4C5",
                                }}
                                className={`w-28 rounded-lg px-2`}
                            >
                                {value === "Deleted" || value === "Disabled" ? (
                                    <p className="text-sm text-[#D32F2F] uppercase text-center">
                                        {value}
                                    </p>
                                ) : (
                                    <p className="text-sm text-[#039855] uppercase text-center">
                                        {value}
                                    </p>
                                )}
                            </div>
                        </div>
                    );
                },
                renderEditCell: (param) => (
                    <GridCellSelect
                        params={param}
                        options={getRecordStatusDropDown(param?.value)}
                        updateHandler={handleInlineUpdates}
                    />
                ),
            },
            {
                field: "action",
                headerName: "Action",
                type: "actions",
                cellClassName: "actions",
                // width: 100,
                groupable: false,
                aggregable: false,
                pinnable: false,
                editable: false,
                filterable: false,
                maxWidth: 120,
                isVisible: true,
                sortable: false,
                renderCell: (params) => {
                    const row = params?.row;
                    return (
                        <TableActionButton
                            ViewBtnClickHandler={viewBtnClickHandler}
                            UpdateBtnClickHandler={EditBtnClickHandler}
                            DeleteBtnClickHandler={deleteBtnClickHandler}
                            row={row}
                            status={"recordStatus"}
                        />
                    );
                },
            },
        ],
        [activityTypeFormField]
    );
Grid Component

And here is the Grid Component

    <DataGridContext.Provider value={{ setIsColumnModalVisible, setIsFilterModalVisible, label }} >
      <div className="custom-grid-header flex justify-between items-center py-4 px-4 bg-[#FCFCFD]">
        <p className="custom-grid-header-label">{label}</p>
        {GridheaderComponent && <GridheaderComponent />}
      </div>
      <DataGridPremium
        checkboxSelection
        apiRef={apiRef}
        unstable_headerFilters
        rows={dataSet}
        columns={columns}
        filterMode="server"
        editMode="cell"
        density="compact"
        sx={{
          maxHeight: "81vh",
          minHeight: "81vh",
          "& .MuiDataGrid-cell:focus-within, & .MuiDataGrid-cell:focus": {
            outline: "none !important",
          },
          "& .MuiDataGrid-columnHeader:focus-within, & .MuiDataGrid-columnHeader:focus":
          {
            outline: "none !important",
          },
          backgroundColor: "#FCFCFD !important",
          '.MuiDataGrid-iconButtonContainer': {
            visibility: 'visible',
          },
          '.MuiDataGrid-sortIcon': {
            opacity: 'inherit !important',
          },
          ".MuiDataGrid-columnHeaderTitle": {
            fontSize: "14px",
            color: "#475467",
            fontFamily: "roboto",
            lineHeight: "16.41px",
            marginRight: "11px",
            fontWeight: 500
          },
          borderWidth: 0,
        }}
        filterDebounceMs={500}
        getRowId={(row) => `${row[rowId]}`}
        pagination
        disableRowSelectionOnClick
        onRowClick={(params) =>
          handleRowClick ? handleRowClick(params) : () => { }
        }
        loading={gridLoading}
        rowCount={totalCount}
        paginationModel={paginationModel}
        onFilterModelChange={(model) => HandleFilterChange(model)}
        paginationMode="server"
        onPaginationModelChange={(model) => handleGridPagination(model)}
        initialState={{
          pagination: { paginationModel: { pageSize: 25, page: 0 } },
          rowGrouping: {
            model: [],
          },
        }}
        pageSizeOptions={[25, 50, 100, 250, 500]}
        slots={{
          toolbar: CustomGridToolBar,
          footer: () => (
            <GridFooterContainer sx={{ display: "flex" }}>
              <div className="flex flex-1">
                <GridFooter sx={{ display: { xs: "none", md: "flex " } }} />
              </div>
              <div className="flex flex-1 justify-end">
                <GridFooterServerPagination
                  pageIndex={pageIndex}
                  setPageIndex={setPageIndex}
                  table={apiRef}
                  totalCount={totalCount}
                />
              </div>
            </GridFooterContainer>
          ),
          columnMenu: CustomColumnMenu,
          columnFilteredIcon: () => <></>,
          columnSortedAscendingIcon: () => <DataGridSortIcon />,
          columnSortedDescendingIcon: () => <DataGridSortIcon />,
        }}
        slotProps={{
          filterPanel: {
            logicOperators: [],
          },
        }}
        columnVisibilityModel={{ ...visbleFeilds }}
        onColumnVisibilityModelChange={(model, details) => {
          setVisibleFeilds({ ...model });
        }}
        isCellEditable={(params) => params.row.status !== "Protected"}
        getRowClassName={getRowClassName}
      />
      {isFilterModalVisible && (
        <CustomGridFilter
          open={isFilterModalVisible}
          handleClose={() => setIsFilterModalVisible(false)}
          gridRef={apiRef}
        />
      )}
      {isColumnModalVisible && (
        <CustomGridColumns
          open={isColumnModalVisible}
          handleClose={() => setIsColumnModalVisible(false)}
          gridRef={apiRef}
        />
      )}
    </DataGridContext.Provider>

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 30, 2024
@michelengelen
Copy link
Member

Is this a v7 grid? or are you still on v6?

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 30, 2024
@Shudhanshu-Appnox
Copy link
Author

@michelengelen V6

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 30, 2024
@michelengelen
Copy link
Member

Did you try updating to v7?
We have reworked the headers and the way they get calculated as well, so this might be the easiest fix for this.

I know that we had some problems with flex values on the columns in the past, thats partially why we did that rework.

If you haven't tried I would recommend updating (its more future proof as well) and if you need assistance we can help with that as well!

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 30, 2024
@Shudhanshu-Appnox
Copy link
Author

Shudhanshu-Appnox commented Apr 30, 2024

@michelengelen OK, sure can you let me know how can I update to V7 ?

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 30, 2024
@michelengelen
Copy link
Member

we do have a migration guide in the docs: Migration

If you need help please feel free to reach out!

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels May 2, 2024
@Shudhanshu-Appnox
Copy link
Author

Shudhanshu-Appnox commented May 3, 2024

@michelengelen Hi, I have updated the Data Grid Version still the issue is not Resolved. Initially, all the column names were blank after some time the Column Header Name was rendered. So, I thought might be it's due to VisibleFeild model so I commented down that but it still does not resolved.

Screen.Recording.2024-05-03.at.12.19.48.PM.mov

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels May 3, 2024
@michelengelen
Copy link
Member

michelengelen commented May 3, 2024

could you try ...

  1. commenting out the headerfilter rendering
  2. using a smaller set of columns
  3. commenting out the custom slots

I noticed from your code block that you use quite a lot of literal decalrations in the props.
It is recommended to extract (and memoize when unstable) these things:

footer: () => (
  <GridFooterContainer sx={{ display: "flex" }}>
    <div className="flex flex-1">
      <GridFooter sx={{ display: { xs: "none", md: "flex " } }} />
    </div>
    <div className="flex flex-1 justify-end">
      <GridFooterServerPagination
        pageIndex={pageIndex}
        setPageIndex={setPageIndex}
        table={apiRef}
        totalCount={totalCount}
      />
    </div>
  </GridFooterContainer>
),

should better be

const CustomGridFooter = () => (
  <GridFooterContainer sx={{ display: "flex" }}>
    <div className="flex flex-1">
      <GridFooter sx={{ display: { xs: "none", md: "flex " } }} />
    </div>
    <div className="flex flex-1 justify-end">
      <GridFooterServerPagination
        pageIndex={pageIndex}
        setPageIndex={setPageIndex}
        table={apiRef}
        totalCount={totalCount}
      />
    </div>
  </GridFooterContainer>
)

...

footer: CustomGridFooter,      // <-- in slots

and similar. This will prevent a few unwanted rerenders. The custom components can also be memoized when parts of it are unstable.

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels May 3, 2024
@Shudhanshu-Appnox
Copy link
Author

Shudhanshu-Appnox commented May 6, 2024

@michelengelen

  1. commenting out the headerfilter rendering [ No Effect ]
  2. using a smaller set of columns [ No Effect ]
  3. commenting out the custom slots [ No Effect ]

Also, I have added GridFooter as a Slot but still there is no Effect on the behaviour.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels May 6, 2024
@michelengelen
Copy link
Member

Interesting... that leaves only one last possibility: Do you fetch header definitions (names, etc.) from the server?

It looks as if the header does get rendered initially, but without content.

A few other things to test:

  1. can you remove the flex values from the column definition and test replacing those with hard coded width values?
  2. maybe removing the minWidth value could also help.

As it stands I haven't seen anything like that before. @MBilalShafi would you have a striking idea here?

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels May 6, 2024
@Shudhanshu-Appnox
Copy link
Author

Shudhanshu-Appnox commented May 6, 2024

@michelengelen By commenting the Flex 1 in the column definition the issue has been resolved but it affects the columns auto adjustment. Is there any other workaround for it?
Also,

  1. I am not fetching the header definition from the server. It's all handled on the Client Side.
  2. By removing the MinWidth there was no effect on the Readjustment Behaviour.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels May 6, 2024
@michelengelen
Copy link
Member

@michelengelen By commenting the Flex 1 in the column definition the issue has been resolved but it affects the columns auto adjustment. Is there any other workaround for it ?

I am not that familiar with the header rendering and autosizing. @romgrk or @MBilalShafi might have a better idea.

@Shudhanshu-Appnox
Copy link
Author

@michelengelen I have fixed the bug, the reason this bug was produced was how i was passing the data set to the DATA GRID by destructing.

// Previous
Screenshot 2024-05-06 at 4 31 49 PM

// Current
Screenshot 2024-05-06 at 4 33 11 PM

@michelengelen
Copy link
Member

Great that you did find the solution for this. Just goes to say that the more acurate the reproduction or code examples are the easier it would have been spotted. :P

@michelengelen michelengelen removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label May 6, 2024
Copy link

github-actions bot commented May 6, 2024

⚠️ 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.

@Shudhanshu-Appnox: 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! support: commercial Support request from paid users support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/
Projects
None yet
Development

No branches or pull requests

3 participants