如何使用DevExtreme React Grid Table与FilteringState和/或LocalFiltering进行OR过滤?

时间:2017-11-22 09:40:35

标签: reactjs material-ui devextreme

根据issue #499下的 open 现已关闭devextreme-reactive github repo,我希望能够在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 个答案:

答案 0 :(得分:1)

在查看过滤代码库后,快速回答是 它不是直接的,但它是可能的。

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

正如我在<{3}}下的 open 现已关闭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 团队实施一种运行复合列过滤的官方方式。

在我们等待的时候,前一个例子应该启动并运行许多用例。

更新

该库的一位开发人员非常友好地提供了(devextreme-reactive github repo)一个实现基于行的自定义过滤器的方法的示例和演示:

首先,使用单个过滤器编辑器创建自定义过滤器行。接下来,使用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开发on the original issue

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