如何使用具有 FilteringState 和/或 LocalFiltering 的 DevExtreme React 网格表进行 OR 过滤?

Posted

技术标签:

【中文标题】如何使用具有 FilteringState 和/或 LocalFiltering 的 DevExtreme React 网格表进行 OR 过滤?【英文标题】:How to do OR filter using DevExtreme React Grid Table with either FilteringState and/or LocalFiltering? 【发布时间】:2018-05-05 23:41:11 【问题描述】:

根据 open 现在在devextreme-reactive github repo 下关闭issue #499,我希望能够在Grid/TableView 组件下进行某种复合过滤。

目前有两个过滤组件,分别举例如下:

FilteringState

import React from 'react';
import 
  FilteringState,
  LocalFiltering,
 from '@devexpress/dx-react-grid';
import 
  Grid,
  TableView,
  TableHeaderRow,
  TableFilterRow,
 from '@devexpress/dx-react-grid-material-ui';

import 
  generateRows,
 from '../../demo-data/generator';

export default class Demo extends React.PureComponent 
  constructor(props) 
    super(props);

    this.state = 
      columns: [
         name: 'name', title: 'Name' ,
         name: 'sex', title: 'Sex' ,
         name: 'city', title: 'City' ,
         name: 'car', title: 'Car' ,
      ],
      rows: generateRows( length: 14 ),
      filters: [ columnName: 'car', value: 'cruze' ],
    ;

    this.changeFilters = filters => this.setState( filters );
  
  render() 
    const  rows, columns  = this.state;

    return (
      <Grid
        rows=rows
        columns=columns
      >
        <FilteringState
          filters=this.state.filters
          onFiltersChange=this.changeFilters
        />
        <LocalFiltering />
        <TableView />
        <TableHeaderRow />
        <TableFilterRow />
      </Grid>
    );
  

LocalFiltering

import React from 'react';
import 
  FilteringState,
  LocalFiltering,
 from '@devexpress/dx-react-grid';
import 
  Grid,
  TableView,
  TableHeaderRow,
  TableFilterRow,
 from '@devexpress/dx-react-grid-material-ui';

import 
  generateRows,
 from '../../demo-data/generator';

const toLowerCase = value => String(value).toLowerCase();
const filterByCity = (value, filter) => toLowerCase(value).startsWith(toLowerCase(filter.value));
const getColumnPredicate = columnName => (columnName === 'city' ? filterByCity : undefined);

export default class Demo extends React.PureComponent 
  constructor(props) 
    super(props);

    this.state = 
      columns: [
         name: 'name', title: 'Name' ,
         name: 'sex', title: 'Sex' ,
         name: 'city', title: 'City' ,
         name: 'car', title: 'Car' ,
      ],
      rows: generateRows( length: 14 ),
    ;
  
  render() 
    const  rows, columns  = this.state;

    return (
      <Grid
        rows=rows
        columns=columns
      >
        <FilteringState defaultFilters=[ columnName: 'city', value: 'Paris' ] />
        <LocalFiltering getColumnPredicate=getColumnPredicate />
        <TableView />
        <TableHeaderRow />
        <TableFilterRow />
      </Grid>
    );
  

这两个示例都受到以下事实的限制:一次只能将一个过滤器应用于指定的每一列。

换句话说,即使我可以创建多个过滤器,但每个过滤器一次只能应用于一列。

例如,假设我有数据:

[
  
    name: 'jane',
    lastName: 'doe',
  ,
  
    name: 'davey',
    lastName: 'jones',
  ,
  
    name: 'walter',
    lastName: 'white',
  ,
]

如果我实现单个SearchBox 组件,onChange() 会将以下过滤器发送到底层FilteringState

[
   columnName: 'name', value: 'd' ,
   columnName: 'lastName', value: 'd' ,
]

然后我会得到No data,因为过滤器被应用为 AND 而不是 OR

有没有办法实现一个触发器来启用/禁用过滤器被视为OR

或者,有没有办法以这种方式发送过滤器?:

[
   columnNames: ['name', 'lastName'], value: 'd' ,
]

【问题讨论】:

【参考方案1】:

查看过滤代码库后,快速回答是这不是直截了当,但有可能。

更新: 该库的一位开发人员已确认有一种过滤行的方法。示例附加到此答案的末尾。

正如我在 open 中提到的,现在在 devextreme-reactive github repo 下关闭了 issue #499,我目前的解决方法是在发送之前预过滤行数据Grid 组件。

根据问题中提供的name / lastName 示例,我建议类似于以下内容:

import React, Component from 'react';
import TextField from 'material-ui/TextField';
import 
  SortingState,
  LocalSorting,
 from '@devexpress/dx-react-grid';
import PropTypes from 'prop-types';
import 
  Grid, TableView, TableHeaderRow
 from '@devexpress/dx-react-grid-material-ui';

export default class MySearchableTableView extends Component 
  filterBySearch = ev => 
    const data = this.props;
    const searchValue = ev.target.value;
    const filteredData = data.filter(
      row => (toLowerCase(row.name).startsWith(toLowerCase(searchValue)) || toLowerCase(row.lastName).startsWith(toLowerCase(searchValue)))
    );
    this.setState(data: filteredData);
  ;

  updateStateFromProps = (props) => 
    this.setState(data: Object.assign(, props.data));
  ;

  componentDidMount() 
    this.updateStateFromProps(this.props);
  

  componentWillReceiveProps(nextProps) 
    this.updateStateFromProps(nextProps);
  

  render() 
    const  data  = this.state;
    const  columns  = this.props;

    return [
      <TextField
        key="text-field-component"
        label="Search"
        fullWidth
        onChange=this.filterBySearch
      />,
      <Grid
        key="grid-component"
        rows=data || []
        columns=columns || []
      >
        <TableView />
        <TableHeaderRow />
        <TableFilterRow />
      </Grid>,
    ];
  

希望在不久的将来,DevExpress 团队实现了一种运行复合列过滤的官方方式。

与此同时,在我们等待的同时,前面的示例应该会启动并运行许多用例。

更新

该库的一位开发人员非常友好地提供了 (on the original issue) 一个示例和演示,说明了一种实现基于行的自定义过滤器的方法:

首先,使用单个过滤器编辑器创建一个自定义过滤器行。接下来,使用 onChange 事件处理程序创建自定义过滤器:

<TableFilterRow
  filterRowTemplate=() => (<TableRow>
      <TableCell>
        <Input
          onChange=(e) => 
            this.setState( filters: [
              
                columnName: 'custom',
                value: e.target.value
              
            ]);
          
        />
      </TableCell>
    </TableRow>
  )
/>

然后,在列谓词中使用此过滤器:

<LocalFiltering
  getColumnPredicate=() => (value, filter, row) => (
    row.firstFieldName.indexOf(filter.value) > -1
    ||
    row.secondFieldName.indexOf(filter.value) > -1
  )
/>

乍一看,这会导致行过滤器运行多次,因为它在getColumnPredicate 下的每行列运行。

再说一遍,devextreme-reactive devs have confirmed:

这取决于过滤器计数,而不是列数。每个过滤器将应用于每一行。

【讨论】:

以上是关于如何使用具有 FilteringState 和/或 LocalFiltering 的 DevExtreme React 网格表进行 OR 过滤?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过使用 dplyr 或其他包在 R 中具有最小值和最大值的查询来实现组?

如何使用 jquery 或 javascript 计算具有特定值的行数?

如何实现具有两个或更多键的哈希函数?

如何使用 Swift 将具有两个不同键的两个值存储到数组或字典中? [关闭]

如何使用 jquery 选择具有或不具有特定“alt”属性的图像

如何创建一个 UIViewController 具有两个视图,根据单击的按钮显示一个或另一个