mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
implement filter
This commit is contained in:
parent
861809d10c
commit
7016e55472
11
packages/react-bootstrap-table2-filter/package.json
Normal file
11
packages/react-bootstrap-table2-filter/package.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "react-bootstrap-table2-filter",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "it's the column filter addon for react-bootstrap-table2",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
||||||
2
packages/react-bootstrap-table2-filter/src/comparison.js
vendored
Normal file
2
packages/react-bootstrap-table2-filter/src/comparison.js
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const LIKE = 'LIKE';
|
||||||
|
export const EQ = '=';
|
||||||
93
packages/react-bootstrap-table2-filter/src/components/text.js
vendored
Normal file
93
packages/react-bootstrap-table2-filter/src/components/text.js
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/* eslint react/require-default-props: 0 */
|
||||||
|
/* eslint react/no-unused-prop-types: 0 */
|
||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { PropTypes } from 'prop-types';
|
||||||
|
|
||||||
|
import { LIKE, EQ } from '../comparison';
|
||||||
|
import { FILTER_TYPE, FILTER_DELAY } from '../const';
|
||||||
|
|
||||||
|
class TextFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
this.timeout = null;
|
||||||
|
this.state = {
|
||||||
|
value: props.defaultValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
const defaultValue = this.input.value;
|
||||||
|
if (defaultValue) {
|
||||||
|
this.props.onFilter(this.props.column, defaultValue, FILTER_TYPE.TEXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (nextProps.defaultValue !== this.props.defaultValue) {
|
||||||
|
this.applyFilter(nextProps.defaultValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
const filterValue = e.target.value;
|
||||||
|
this.setState(() => ({ value: filterValue }));
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.props.onFilter(this.props.column, filterValue, FILTER_TYPE.TEXT);
|
||||||
|
}, this.props.delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanFiltered() {
|
||||||
|
const value = this.props.defaultValue;
|
||||||
|
this.setState(() => ({ value }));
|
||||||
|
this.props.onFilter(this.props.column, value, FILTER_TYPE.TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(filterText) {
|
||||||
|
this.setState(() => ({ value: filterText }));
|
||||||
|
this.props.onFilter(this.props.column, filterText, FILTER_TYPE.TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { placeholder, column: { text }, style } = this.props;
|
||||||
|
// stopPropagation for onClick event is try to prevent sort was triggered.
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ n => this.input = n }
|
||||||
|
type="text"
|
||||||
|
className="filter text-filter form-control"
|
||||||
|
style={ style }
|
||||||
|
onChange={ this.filter }
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
|
placeholder={ placeholder || `Enter ${text}...` }
|
||||||
|
value={ this.state.value }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFilter.propTypes = {
|
||||||
|
onFilter: PropTypes.func.isRequired,
|
||||||
|
comparator: PropTypes.oneOf([LIKE, EQ]),
|
||||||
|
defaultValue: PropTypes.string,
|
||||||
|
delay: PropTypes.number,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
column: PropTypes.object,
|
||||||
|
style: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
TextFilter.defaultProps = {
|
||||||
|
delay: FILTER_DELAY,
|
||||||
|
defaultValue: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default TextFilter;
|
||||||
5
packages/react-bootstrap-table2-filter/src/const.js
vendored
Normal file
5
packages/react-bootstrap-table2-filter/src/const.js
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const FILTER_TYPE = {
|
||||||
|
TEXT: 'TEXT'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FILTER_DELAY = 500;
|
||||||
36
packages/react-bootstrap-table2-filter/src/filter.js
vendored
Normal file
36
packages/react-bootstrap-table2-filter/src/filter.js
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { FILTER_TYPE } from './const';
|
||||||
|
import { LIKE, EQ } from './comparison';
|
||||||
|
|
||||||
|
export const filterByText = _ => (data, dataField, { filterVal, comparator = LIKE }) =>
|
||||||
|
data.filter((row) => {
|
||||||
|
const cell = _.get(row, dataField);
|
||||||
|
const cellStr = _.isDefined(cell) ? cell.toString() : '';
|
||||||
|
if (comparator === EQ) {
|
||||||
|
return cellStr === filterVal;
|
||||||
|
}
|
||||||
|
return cellStr.indexOf(filterVal) > -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const filterFactory = _ => (filterType) => {
|
||||||
|
let filterFn;
|
||||||
|
switch (filterType) {
|
||||||
|
case FILTER_TYPE.TEXT:
|
||||||
|
filterFn = filterByText(_);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
filterFn = filterByText(_);
|
||||||
|
}
|
||||||
|
return filterFn;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filters = (store, _) => (currFilters) => {
|
||||||
|
const factory = filterFactory(_);
|
||||||
|
let result = store.getAllData();
|
||||||
|
let filterFn;
|
||||||
|
Object.keys(currFilters).forEach((dataField) => {
|
||||||
|
const filterObj = currFilters[dataField];
|
||||||
|
filterFn = factory(filterObj.filterType);
|
||||||
|
result = filterFn(result, dataField, filterObj);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
15
packages/react-bootstrap-table2-filter/src/index.js
vendored
Normal file
15
packages/react-bootstrap-table2-filter/src/index.js
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import TextFilter from './components/text';
|
||||||
|
import FilterWrapper from './wrapper';
|
||||||
|
import * as Comparison from './comparison';
|
||||||
|
|
||||||
|
export default (options = {}) => ({
|
||||||
|
FilterWrapper,
|
||||||
|
options
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Comparator = Comparison;
|
||||||
|
|
||||||
|
export const textFilter = (props = {}) => ({
|
||||||
|
Filter: TextFilter,
|
||||||
|
props
|
||||||
|
});
|
||||||
48
packages/react-bootstrap-table2-filter/src/wrapper.js
vendored
Normal file
48
packages/react-bootstrap-table2-filter/src/wrapper.js
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { filters } from './filter';
|
||||||
|
|
||||||
|
export default class FilterWrapper extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
store: PropTypes.object.isRequired,
|
||||||
|
baseElement: PropTypes.func.isRequired,
|
||||||
|
_: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { currFilters: {}, isDataChanged: false };
|
||||||
|
this.onFilter = this.onFilter.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps() {
|
||||||
|
this.setState(() => ({ isDataChanged: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
onFilter(column, filterVal, filterType) {
|
||||||
|
const { store, _ } = this.props;
|
||||||
|
const { currFilters } = this.state;
|
||||||
|
const { dataField, filter } = column;
|
||||||
|
|
||||||
|
if (!_.isDefined(filterVal) || filterVal === '') {
|
||||||
|
delete currFilters[dataField];
|
||||||
|
} else {
|
||||||
|
const { comparator } = filter.props;
|
||||||
|
currFilters[dataField] = { filterVal, filterType, comparator };
|
||||||
|
}
|
||||||
|
|
||||||
|
store.filteredData = filters(store, _)(currFilters);
|
||||||
|
store.filtering = Object.keys(currFilters).length > 0;
|
||||||
|
|
||||||
|
this.setState(() => ({ currFilters, isDataChanged: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return this.props.baseElement({
|
||||||
|
...this.props,
|
||||||
|
key: 'table',
|
||||||
|
onFilter: this.onFilter,
|
||||||
|
isDataChanged: this.state.isDataChanged
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,11 +6,13 @@ import { getRowByRowId } from './rows';
|
|||||||
export default class Store {
|
export default class Store {
|
||||||
constructor(keyField) {
|
constructor(keyField) {
|
||||||
this._data = [];
|
this._data = [];
|
||||||
|
this._filteredData = [];
|
||||||
this._keyField = keyField;
|
this._keyField = keyField;
|
||||||
|
|
||||||
this._sortOrder = undefined;
|
this._sortOrder = undefined;
|
||||||
this._sortField = undefined;
|
this._sortField = undefined;
|
||||||
this._selected = [];
|
this._selected = [];
|
||||||
|
this._filtering = false;
|
||||||
|
this._isDataChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
edit(rowId, dataField, newValue) {
|
edit(rowId, dataField, newValue) {
|
||||||
@ -24,12 +26,33 @@ export default class Store {
|
|||||||
this.data = sort(this)(sortFunc);
|
this.data = sort(this)(sortFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
get data() { return this._data; }
|
getAllData() {
|
||||||
set data(data) { this._data = (data ? JSON.parse(JSON.stringify(data)) : []); }
|
return this._data;
|
||||||
|
}
|
||||||
|
|
||||||
|
get data() {
|
||||||
|
if (this._filtering) {
|
||||||
|
return this._filteredData;
|
||||||
|
}
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
set data(data) {
|
||||||
|
if (this._filtering) {
|
||||||
|
this._filteredData = data;
|
||||||
|
} else {
|
||||||
|
this._data = (data ? JSON.parse(JSON.stringify(data)) : []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get filteredData() { return this._filteredData; }
|
||||||
|
set filteredData(filteredData) { this._filteredData = filteredData; }
|
||||||
|
|
||||||
get keyField() { return this._keyField; }
|
get keyField() { return this._keyField; }
|
||||||
set keyField(keyField) { this._keyField = keyField; }
|
set keyField(keyField) { this._keyField = keyField; }
|
||||||
|
|
||||||
|
get isDataChanged() { return this._isDataChanged; }
|
||||||
|
set isDataChanged(isDataChanged) { this._isDataChanged = isDataChanged; }
|
||||||
|
|
||||||
get sortOrder() { return this._sortOrder; }
|
get sortOrder() { return this._sortOrder; }
|
||||||
set sortOrder(sortOrder) { this._sortOrder = sortOrder; }
|
set sortOrder(sortOrder) { this._sortOrder = sortOrder; }
|
||||||
|
|
||||||
@ -38,4 +61,7 @@ export default class Store {
|
|||||||
|
|
||||||
get selected() { return this._selected; }
|
get selected() { return this._selected; }
|
||||||
set selected(selected) { this._selected = selected; }
|
set selected(selected) { this._selected = selected; }
|
||||||
|
|
||||||
|
get filtering() { return this._filtering; }
|
||||||
|
set filtering(filtering) { this._filtering = filtering; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,8 @@ export const pureTable = props =>
|
|||||||
|
|
||||||
export const wrapWithFilter = (props) => {
|
export const wrapWithFilter = (props) => {
|
||||||
if (props.filter) {
|
if (props.filter) {
|
||||||
const { wrapper } = props.filter;
|
const { FilterWrapper } = props.filter;
|
||||||
const FilterBase = wrapper(wrapWithSort, _);
|
return React.createElement(FilterWrapper, { ...props, baseElement: wrapWithSort, _ });
|
||||||
return React.createElement(FilterBase, { ...props });
|
|
||||||
}
|
}
|
||||||
return wrapWithSort(props);
|
return wrapWithSort(props);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user