简体   繁体   中英

Get filtred data, react-bootstrap-table2

Is there any global table option that return the filtred rows? Ignore pagination. All rows matching one or several textFilter ?

I need a value in the header showin the average value of the filtred data.

I don't find any on https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html

There is the onDataSizeChange , but it only gives the prop dataSize (nr of rows), also only available when pagination is not used.

Update to second question in comments:

class App extends Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);

    this.state = {
      data: [...]
      filtredData: null
    };
  };

  const factory = patchFilterFactory(filterFactory, (filteredData) => {
     this.setState({filteredData}); // causes maximum update exceeded..
  });

  render() {
    return (
      <div>
         <BootstrapTable
          keyField='id'
          striped
          hover
          bootstrap4
          data={anbuds}
          filter={factory()}
          columns={columns}/>
      </div>
    );
  }
}

Kinda.

One way you could do that is by providing a different implementation of the filter prop, and get the data that you need there.

import BootstrapTable from "react-bootstrap-table-next";
import filterFactory, { textFilter } from "react-bootstrap-table2-filter";

function patchFilterFactory(filterFactory, onFilteredData) {
  return (...args) => {
    const { createContext, options } = filterFactory(...args)
    return {
      createContext: (...args) => {
        const { Provider: BaseProvider, Consumer } = createContext(...args)
        const Provider = class FilterProvider extends BaseProvider {
          componentDidUpdate() {
            onFilteredData(this.data)
          }
        }
        return { Provider, Consumer } 
      },
      options
    }
  }
}

patchFilterFactory will just sit in between the original filter provider and your code, allowing you to get the data that you need.

How to use it:

function Table() {
  const columns = [
    {
      dataField: "id",
      text: "Product ID"
    },
    {
      dataField: "name",
      text: "Product Name",
      filter: textFilter({
        delay: 0
      })
    },
    {
      dataField: "price",
      text: "Product Price",
      filter: textFilter({
        delay: 0
      })
    }
  ];

  const factory = patchFilterFactory(filterFactory, (filteredData) => {
    console.log('on filter data', filteredData)
  })

  return (
      <BootstrapTable
        keyField="id"
        data={props.products}
        columns={columns}
        filter={factory()}
      />
  );
}

I agree, that's far from ideal, but as far as I was able to assess, it may be the only way at the moment.

If you want to change state in the same component, I would recommend:

  const [filteredData, setFilteredData] = React.useState([])

  const factory = patchFilterFactory(filterFactory, data => {
    setFilteredData(prevData => {
      if (JSON.stringify(prevData) !== JSON.stringify(data)) {
        return data
      }

      return prevData
    })
  })

My 2¢: after some investigation (and intentionally avoiding implementation of filter factory wrapper suggested by @federkun) I found out I can access current filter context of rendered table.

In order to access table properties, I had to add React Ref :

class MyDataTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: props.data
    };
    this.node = React.createRef();
  }

  ...

  render() {
    return (
      <Card>
        <CardBody>
          <BootstrapTable
            ref={n => this.node = n}
            keyField="id"
            data={this.state.data}
            ...
          />
          <Button name="click-me" onClick={() => this.handleClick()}>Click me!</Button>
        </CardBody>
      </Card>
    )
  }
}

Now when it is possible to reference <BootstrapTable> from code using this.node , I can get to all filtered data (without paging):

  // member of MyDataTable component
  handleClick() {
    console.log(this.node.filterContext.data);
  }

Please note that if you access data this way, entries won't be sorted as you see it in the table, so if you want to go really crazy, you can get data filtered and sorted this way:

  // member of MyDataTable component
  handleClick() {
    const table = this.node;
    const currentDataView =
      (table.paginationContext && table.paginationContext.props.data)
      || (table.sortContext && table.sortContext.props.data) // <- .props.data (!)
      || (table.filterContext && table.filterContext.data) // <- .data (!)
      || this.state.data; // <- fallback

    console.log(currentDataView);
  }

... however this is becoming pretty wild. Important thing here is to start with paginationContext - anything before it is already sliced into pages. You can check how contexts are put together here: react-bootstrap-table2/src/contexts/index.js .

Nevertheless, this approach is hacky - completely avoiding public API, intercepting context pipeline, reading inputs for each layer. Things may change in newer releases, or there may be issue with this approach I haven't discovered yet - just be aware of that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM