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.05k stars 1.25k forks source link

[data grid] New row not visible when filter is set #14361

Closed MacHankus closed 1 week ago

MacHankus commented 2 weeks ago

Steps to reproduce

Link to live example: [(required)](https://codesandbox.io/p/sandbox/add-record-with-filters-xhkxrn)

Steps:

  1. Add Filter Select column name. Select Operator. Provide value. Click somewhere to hide filter panel.
  2. Add record. Click Add Record button.

After this steps you can see that new row doesn't appear anywhere. You can see new record only if filter is off.

I didn't find any information about how new row should behave. Is it any tip to make new rows always visible with or without filters ? I know that probably filters are doing its job and new row is filtered out , but the question is why ? From the business side the row is added as soon as we click save not before so filters should not affect new rows. We can update rows when filters are set but we cannot add new rows.

Current behavior

New row is not visible when filter is set

Expected behavior

New row should be visible when filter is set ?

Context

I want to add new row and set cell values based on visible rows. Right now i need to open second browser tab with filtered values to browse them and keep open browser tab without filters to add rows.

Your environment

npx @mui/envinfo ``` Chrome 127.0.6533.122 ```

Search keywords: New row not visible when filter is set

dosubot[bot] commented 2 weeks ago

Hey there, @MacHankus! I'm here to assist you with any bugs, questions, or contributions you may have regarding the repository. Let me know how I can help you!

I found a similar closed issue that might be relevant: [data grid] Add row while filter is active [1].

To make a new row visible in the Data Grid when a filter is set, you need to ensure that the row passes the current filters applied to the grid. This involves updating the filteredRowsLookup to include the new row and setting its value to true.

Here is an example of how you might update the filteredRowsLookup to make a new row visible:

import { GridFilterState, GridRowId } from '../../../models/gridFilterState';

// Assuming you have the new row's ID and the current filter state
const newRowId: GridRowId = 'new-row-id';
const currentFilterState: GridFilterState = {
  filterModel: {
    items: [],
    logicOperator: 'and',
    quickFilterValues: [],
    quickFilterLogicOperator: 'and',
  },
  filteredRowsLookup: {},
  filteredChildrenCountLookup: {},
  filteredDescendantCountLookup: {},
};

// Update the filteredRowsLookup to include the new row and set it to true
currentFilterState.filteredRowsLookup[newRowId] = true;

// Now the new row should be visible if it passes the filters

Additionally, you can use the upsertFilterItems API method to add or update filter items dynamically. This method ensures that the new row is evaluated against the current filters and made visible if it passes them.

Here is an example of how to use the upsertFilterItems method:

import { useGridApiRef, DataGridPro } from '@mui/x-data-grid-pro';
import { act } from 'react-dom/test-utils';

const apiRef = useGridApiRef();

const newFilterItems = [
  {
    field: 'brand',
    value: 'new-value',
    operator: 'contains',
    id: 1,
  },
];

act(() => {
  apiRef.current.upsertFilterItems(newFilterItems);
});

For more advanced customization, you can use a custom filter panel. Below is an example of how to set up a custom filter panel in the Data Grid:

import * as React from 'react';
import { DataGridPro, GridLogicOperator, GridToolbar } from '@mui/x-data-grid-pro';
import { useDemoData } from '@mui/x-data-grid-generator';
const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin'];

export default function CustomFilterPanelContent() {
  const { data } = useDemoData({
    dataSet: 'Employee',
    visibleFields: VISIBLE_FIELDS,
    rowLength: 100,
  });
  return (
    <div style={{ height: 400, width: '100%' }}>
      <DataGridPro
        {...data}
        slots={{
          toolbar: GridToolbar,
          // Use custom FilterPanel only for deep modification
          // FilterPanel: MyCustomFilterPanel,
        }}
        slotProps={{
          filterPanel: {
            // Force usage of "And" operator
            logicOperators: [GridLogicOperator.And],
            // Display columns by ascending alphabetical order
            columnsSort: 'asc',
            filterFormProps: {
              // Customize inputs by passing props
              logicOperatorInputProps: {
                variant: 'outlined',
                size: 'small',
              },
              columnInputProps: {
                variant: 'outlined',
                size: 'small',
                sx: { mt: 'auto' },
              },
              operatorInputProps: {
                variant: 'outlined',
                size: 'small',
                sx: { mt: 'auto' },
              },
              valueInputProps: {
                InputComponentProps: {
                  variant: 'outlined',
                  size: 'small',
                },
              },
              deleteIconProps: {
                sx: {
                  '& .MuiSvgIcon-root': { color: '#d32f2f' },
                },
              },
            },
            sx: {
              // Customize inputs using css selectors
              '& .MuiDataGrid-filterForm': { p: 2 },
              '& .MuiDataGrid-filterForm:nth-child(even)': {
                backgroundColor: (theme) =>
                  theme.palette.mode === 'dark' ? '#444' : '#f5f5f5',
              },
              '& .MuiDataGrid-filterFormLogicOperatorInput': { mr: 2 },
              '& .MuiDataGrid-filterFormColumnInput': { mr: 2, width: 150 },
              '& .MuiDataGrid-filterFormOperatorInput': { mr: 2 },
              '& .MuiDataGrid-filterFormValueInput': { width: 200 },
            },
          },
        }}
        initialState={{
          ...data.initialState,
          filter: {
            ...data.initialState?.filter,
            filterModel: {
              items: [
                {
                  id: 1,
                  field: 'name',
                  operator: 'contains',
                  value: 'D',
                },
                {
                  id: 2,
                  field: 'name',
                  operator: 'contains',
                  value: 'D',
                },
                {
                  id: 3,
                  field: 'rating',
                  operator: '>',
                  value: '0',
                },
              ],
            },
          },
        }}
      />
    </div>
  );
}

This example demonstrates how to customize the filter panel to ensure that new rows are evaluated and made visible if they match the filter criteria [2][3][4].

To continue talking to Dosu, mention @dosu.

MacHankus commented 2 weeks ago

If it comes to first example how can i set currentFilterState.filteredRowsLookup[newRowId] = true; properly ? Should I maintain filterModel by my own while doing this or can i just update filteredRowsLookup and not bother about maintaining filterModel ? Is there any example of this code with actual DataGrid instance ?

michelengelen commented 2 weeks ago

Hey @MacHankus ... what you are trying to do is probably not possible. We can currently exclude columns from the filtering, but not rows.

Thinking about this there might be a way. But first: Do you need this for all columns, or just for specific ones?

I am asking because the workaround would include adjusting the applyfilter functions for the operators and would essentially remove the isEmpty operator in general.

github-actions[bot] commented 1 week ago

The issue has been inactive for 7 days and has been automatically closed.