diff --git a/packages/grid/_modules_/grid/components/panel/filterPanel/GridFilterInputValue.tsx b/packages/grid/_modules_/grid/components/panel/filterPanel/GridFilterInputValue.tsx index 5f6dcc0b04bd5..fdd13b7ccf8c8 100644 --- a/packages/grid/_modules_/grid/components/panel/filterPanel/GridFilterInputValue.tsx +++ b/packages/grid/_modules_/grid/components/panel/filterPanel/GridFilterInputValue.tsx @@ -69,11 +69,6 @@ function GridFilterInputValue(props: GridTypeFilterInputValueProps & TextFieldPr clearTimeout(filterTimeout.current); setFilterValueState(String(value)); - if (type !== 'singleSelect' && value === '') { - setIsApplying(false); - return; - } - setIsApplying(true); // TODO singleSelect doesn't debounce filterTimeout.current = setTimeout(() => { diff --git a/packages/grid/_modules_/grid/models/colDef/gridNumericColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridNumericColDef.ts index 09d8eec0126cd..72a570e6e3e3e 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridNumericColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridNumericColDef.ts @@ -10,7 +10,7 @@ export const GRID_NUMERIC_COL_DEF: GridColTypeDef = { align: 'right', headerAlign: 'right', sortComparator: gridNumberComparer, - valueParser: (value) => Number(value), + valueParser: (value) => (value === '' ? null : Number(value)), valueFormatter: ({ value }) => (value && isNumber(value) && value.toLocaleString()) || value, filterOperators: getGridNumericColumnOperators(), }; diff --git a/packages/grid/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx index 6b4533042174e..a19299550d9c1 100644 --- a/packages/grid/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/filtering.DataGridPro.test.tsx @@ -228,6 +228,32 @@ describe(' - Filter', () => { expect(getColumnValues()).to.deep.equal([]); }); + it('should call onFilterModelChange when the value is emptied', () => { + const onFilterModelChange = spy(); + render( + , + ); + expect(onFilterModelChange.callCount).to.equal(0); + fireEvent.change(screen.queryByRole('textbox', { name: 'Value' }), { target: { value: '' } }); + clock.tick(500); + expect(onFilterModelChange.callCount).to.equal(1); + }); + it('should only select visible rows', () => { const newModel: GridFilterModel = { items: [ diff --git a/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx index 7bbd60ff71d48..989f46e3b0166 100644 --- a/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/filtering.DataGrid.test.tsx @@ -1,18 +1,23 @@ import * as React from 'react'; import { createRenderer, fireEvent, screen, getByText } from '@material-ui/monorepo/test/utils'; import { expect } from 'chai'; -import { - DataGrid, - GridToolbar, - GridPreferencePanelsValue, - GridInitialState, - DataGridProps, -} from '@mui/x-data-grid'; +import { useFakeTimers } from 'sinon'; +import { DataGrid, GridToolbar, GridPreferencePanelsValue, DataGridProps } from '@mui/x-data-grid'; import { getColumnValues } from 'test/utils/helperFn'; const isJSDOM = /jsdom/.test(window.navigator.userAgent); describe(' - Filter', () => { + let clock; + + beforeEach(() => { + clock = useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); + }); + const { render } = createRenderer(); const baselineProps = { @@ -60,15 +65,14 @@ describe(' - Filter', () => { ], }; - const TestCase = (props: { - rows?: any[]; - columns?: any[]; - operatorValue?: string; - value?: any; - field?: string; - initialState?: GridInitialState; - columnTypes?: any; - }) => { + const TestCase = ( + props: { + columns?: any[]; + operatorValue?: string; + value?: any; + field?: string; + } & Partial>, + ) => { const { operatorValue, value, rows, columns, field = 'brand', ...other } = props; return (
@@ -86,6 +90,12 @@ describe(' - Filter', () => { ], }} disableColumnFilter={false} + initialState={{ + preferencePanel: { + open: true, + openedPanelValue: GridPreferencePanelsValue.filters, + }, + }} {...other} />
@@ -303,6 +313,42 @@ describe(' - Filter', () => { }); }); + ['contains', 'startsWith', 'equals', 'endsWith'].forEach((operatorValue) => { + it(`should show all rows when the value is '' and operator='${operatorValue}'`, () => { + render( + , + ); + expect(getColumnValues()).to.deep.equal(['Asics', 'RedBull', 'Hugo']); + fireEvent.change(screen.getByRole('combobox', { name: 'Operators' }), { + target: { value: operatorValue }, + }); + const input = screen.getByRole('textbox', { name: 'Value' }); + fireEvent.change(input, { target: { value: 'abc' } }); + clock.tick(500); + expect(getColumnValues()).to.deep.equal([]); + fireEvent.change(input, { target: { value: '' } }); + clock.tick(500); + expect(getColumnValues()).to.deep.equal(['Asics', 'RedBull', 'Hugo']); + }); + }); + describe('RegExp', () => { ['contains', 'startsWith', 'endsWith'].forEach((operatorValue) => { it('should escape RegExp characters if applied as filter values', () => { @@ -441,6 +487,31 @@ describe(' - Filter', () => { ); expect(getColumnValues(0)).to.deep.equal(['0', '2']); }); + + it('should show all rows when the value is empty', () => { + render( + String(value) }, + ]} + rows={[ + { id: 2, brand: 0 }, + { id: 3, brand: 1984 }, + { id: 4, brand: 1954 }, + { id: 5, brand: 1974 }, + ]} + />, + ); + expect(getColumnValues()).to.deep.equal(['0', '1984', '1954', '1974']); + const input = screen.getByRole('spinbutton', { name: 'Value' }); + fireEvent.change(input, { target: { value: 999999 } }); + clock.tick(500); + expect(getColumnValues()).to.deep.equal([]); + fireEvent.change(input, { target: { value: '' } }); + clock.tick(500); + expect(getColumnValues()).to.deep.equal(['0', '1984', '1954', '1974']); + }); }); describe('date operators', () => { @@ -851,12 +922,6 @@ describe(' - Filter', () => { ]} field="voltage" operatorValue="is" - initialState={{ - preferencePanel: { - open: true, - openedPanelValue: GridPreferencePanelsValue.filters, - }, - }} />, ); expect(getColumnValues()).to.deep.equal(['Hair Dryer', 'Dishwasher', 'Microwave']); @@ -882,12 +947,6 @@ describe(' - Filter', () => { ]} field="voltage" operatorValue="is" - initialState={{ - preferencePanel: { - open: true, - openedPanelValue: GridPreferencePanelsValue.filters, - }, - }} />, ); expect(getColumnValues()).to.deep.equal(['Hair Dryer', 'Dishwasher', 'Microwave']); @@ -906,12 +965,6 @@ describe(' - Filter', () => { columns={[{ field: 'name' }, { field: 'voltage', type: 'singleSelect' }]} field="voltage" operatorValue="is" - initialState={{ - preferencePanel: { - open: true, - openedPanelValue: GridPreferencePanelsValue.filters, - }, - }} />, ); expect(getColumnValues()).to.deep.equal(['Hair Dryer', 'Dishwasher', 'Microwave']); @@ -966,18 +1019,7 @@ describe(' - Filter', () => { }); it('should work with numeric values', () => { - const { setProps } = render( - , - ); + const { setProps } = render(); expect(getColumnValues()).to.deep.equal(['Nike', 'Adidas', 'Puma']); setProps({ value: 2 }); expect(getColumnValues()).to.deep.equal(['Puma']); @@ -1100,18 +1142,7 @@ describe(' - Filter', () => { describe('Filter preference panel', () => { it('should show an empty string as the default filter input value', () => { - render( - , - ); + render(); expect(screen.getByRole('textbox', { name: 'Value' }).value).to.equal(''); }); });