Skip to content

Commit 1a5084a

Browse files
authored
feat: add the option to change the filter operator (#816)
1 parent 75b559b commit 1a5084a

File tree

4 files changed

+141
-4
lines changed

4 files changed

+141
-4
lines changed

__tests__/demo/demo-components/index.js

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import React, { useState, useEffect, useRef } from 'react';
22

3-
import { Box, Input, InputAdornment } from '@mui/material';
3+
import {
4+
Box,
5+
Input,
6+
InputAdornment,
7+
TextField,
8+
Select,
9+
MenuItem
10+
} from '@mui/material';
411
import SearchIcon from '@mui/icons-material/Search';
512

613
// root of this project
@@ -1467,3 +1474,122 @@ export function LocalizationWithCustomComponents() {
14671474
/>
14681475
);
14691476
}
1477+
1478+
function CustomFilterWithOperatorSelection({ columnDef, onFilterChanged }) {
1479+
const [operator, setOperator] = React.useState('=');
1480+
const [value, setValue] = React.useState(undefined);
1481+
const operatorRef = React.useRef(operator);
1482+
const valueRef = React.useRef(value);
1483+
1484+
React.useEffect(() => {
1485+
if (operatorRef.current !== operator || valueRef.current !== value) {
1486+
onFilterChanged(columnDef.tableData.id, value, operator);
1487+
operatorRef.current = operator;
1488+
valueRef.current = value;
1489+
}
1490+
}, [operator, value]);
1491+
1492+
return (
1493+
<span>
1494+
<Select
1495+
labelId="demo-simple-select-label"
1496+
id="demo-simple-select"
1497+
variant="standard"
1498+
value={operator}
1499+
onChange={(e) => setOperator(e.target.value)}
1500+
>
1501+
<MenuItem value={'='}>=</MenuItem>
1502+
<MenuItem value={'>'}>&gt;</MenuItem>
1503+
<MenuItem value={'<'}>&lt;</MenuItem>
1504+
</Select>
1505+
<TextField
1506+
variant="standard"
1507+
onChange={(e) => setValue(e.target.value)}
1508+
/>
1509+
</span>
1510+
);
1511+
}
1512+
1513+
const columns_with_custom_filter = [
1514+
{ title: 'Name', field: 'name', filtering: true },
1515+
{
1516+
title: 'Some Number',
1517+
field: 'some_number',
1518+
filtering: true,
1519+
filterComponent: ({ columnDef, onFilterChanged }) => (
1520+
<CustomFilterWithOperatorSelection
1521+
columnDef={columnDef}
1522+
onFilterChanged={onFilterChanged}
1523+
/>
1524+
)
1525+
}
1526+
];
1527+
1528+
const data_with_custom_filter = [
1529+
{ name: 'Juan', some_number: 1 },
1530+
{ name: 'John', some_number: 4 },
1531+
{ name: 'Pedro', some_number: 8 },
1532+
{ name: 'Mary', some_number: 12 },
1533+
{ name: 'Oliver', some_number: 2 },
1534+
{ name: 'Ignacio', some_number: 4 }
1535+
];
1536+
1537+
export function FilterWithOperatorSelection() {
1538+
return (
1539+
<MaterialTable
1540+
data={(query) =>
1541+
new Promise((resolve, _reject) => {
1542+
if (query.filters.length > 0) {
1543+
query.filters.forEach((filter) => {
1544+
if (
1545+
filter.value !== undefined &&
1546+
filter.value !== null &&
1547+
filter.value !== ''
1548+
) {
1549+
switch (filter.operator) {
1550+
case '=':
1551+
resolve({
1552+
data: data_with_custom_filter.filter(
1553+
(row) => row[filter.column.field] == filter.value
1554+
),
1555+
page: 1,
1556+
totalCount: data_with_custom_filter.length
1557+
});
1558+
break;
1559+
case '>':
1560+
resolve({
1561+
data: data_with_custom_filter.filter(
1562+
(row) => row[filter.column.field] > filter.value
1563+
),
1564+
page: 1,
1565+
totalCount: data_with_custom_filter.length
1566+
});
1567+
break;
1568+
case '<':
1569+
resolve({
1570+
data: data_with_custom_filter.filter(
1571+
(row) => row[filter.column.field] < filter.value
1572+
),
1573+
page: 1,
1574+
totalCount: data_with_custom_filter.length
1575+
});
1576+
break;
1577+
}
1578+
}
1579+
});
1580+
}
1581+
resolve({
1582+
data: data_with_custom_filter,
1583+
page: 1,
1584+
totalCount: data_with_custom_filter.length
1585+
});
1586+
})
1587+
}
1588+
columns={columns_with_custom_filter}
1589+
options={{
1590+
search: false,
1591+
filtering: true
1592+
}}
1593+
/>
1594+
);
1595+
}

__tests__/demo/demo.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
TableWithSummary,
4949
TableWithNumberOfPagesAround,
5050
FixedColumnWithEdit,
51+
FilterWithOperatorSelection,
5152
TableMultiSorting,
5253
LocalizationWithCustomComponents
5354
} from './demo-components';
@@ -154,6 +155,8 @@ function Demo() {
154155
<FixedColumnWithEdit />
155156
<h1>Localization with Custom Components</h1>
156157
<LocalizationWithCustomComponents />
158+
<h1>Filter with operator selection</h1>
159+
<FilterWithOperatorSelection />
157160
<h1>Remote Data Related</h1>
158161
<ol>
159162
<li>

src/material-table.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -788,8 +788,9 @@ export default class MaterialTable extends React.Component {
788788
}
789789
}, this.props.options.debounceInterval);
790790

791-
onFilterChange = (columnId, value) => {
791+
onFilterChange = (columnId, value, operator = '=') => {
792792
this.dataManager.changeFilterValue(columnId, value);
793+
this.dataManager.changeFilterOperator(columnId, operator);
793794
this.setState({}, this.onFilterChangeDebounce);
794795
};
795796

@@ -801,7 +802,7 @@ export default class MaterialTable extends React.Component {
801802
.filter((a) => a.tableData.filterValue)
802803
.map((a) => ({
803804
column: a,
804-
operator: '=',
805+
operator: a.tableData.filterOperator,
805806
value: a.tableData.filterValue
806807
}));
807808

@@ -815,7 +816,7 @@ export default class MaterialTable extends React.Component {
815816
.filter((a) => a.tableData.filterValue)
816817
.map((a) => ({
817818
column: a,
818-
operator: '=',
819+
operator: a.tableData.filterOperator,
819820
value: a.tableData.filterValue
820821
}));
821822
this.props.onFilterChange(appliedFilters);

src/utils/data-manager.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,13 @@ export default class DataManager {
273273
this.filtered = false;
274274
}
275275

276+
changeFilterOperator(columnId, operator) {
277+
const column = this.columns.find((c) => c.tableData.id === columnId);
278+
279+
column.tableData.filterOperator = operator;
280+
this.filtered = false;
281+
}
282+
276283
changeRowSelected(checked, path) {
277284
const rowData = this.findDataByPath(this.sortedData, path);
278285
rowData.tableData.checked = checked;

0 commit comments

Comments
 (0)