mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
implement number filter
This commit is contained in:
parent
ca32eee28e
commit
28a1077bad
@ -1,5 +1,6 @@
|
|||||||
import TextFilter from './src/components/text';
|
import TextFilter from './src/components/text';
|
||||||
import SelectFilter from './src/components/select';
|
import SelectFilter from './src/components/select';
|
||||||
|
import NumberFilter from './src/components/number';
|
||||||
import wrapperFactory from './src/wrapper';
|
import wrapperFactory from './src/wrapper';
|
||||||
import * as Comparison from './src/comparison';
|
import * as Comparison from './src/comparison';
|
||||||
|
|
||||||
@ -19,3 +20,8 @@ export const selectFilter = (props = {}) => ({
|
|||||||
Filter: SelectFilter,
|
Filter: SelectFilter,
|
||||||
props
|
props
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const numberFilter = (props = {}) => ({
|
||||||
|
Filter: NumberFilter,
|
||||||
|
props
|
||||||
|
});
|
||||||
|
|||||||
@ -1,2 +1,7 @@
|
|||||||
export const LIKE = 'LIKE';
|
export const LIKE = 'LIKE';
|
||||||
export const EQ = '=';
|
export const EQ = '=';
|
||||||
|
export const NE = '!=';
|
||||||
|
export const GT = '>';
|
||||||
|
export const GE = '>=';
|
||||||
|
export const LT = '<';
|
||||||
|
export const LE = '<=';
|
||||||
|
|||||||
249
packages/react-bootstrap-table2-filter/src/components/number.js
vendored
Normal file
249
packages/react-bootstrap-table2-filter/src/components/number.js
vendored
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import * as Comparator from '../comparison';
|
||||||
|
import { FILTER_TYPE, FILTER_DELAY } from '../const';
|
||||||
|
|
||||||
|
const legalComparators = [
|
||||||
|
Comparator.EQ,
|
||||||
|
Comparator.NE,
|
||||||
|
Comparator.GT,
|
||||||
|
Comparator.GE,
|
||||||
|
Comparator.LT,
|
||||||
|
Comparator.LE
|
||||||
|
];
|
||||||
|
|
||||||
|
class NumberFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.comparators = props.comparators || legalComparators;
|
||||||
|
this.timeout = null;
|
||||||
|
let isSelected = props.defaultValue !== undefined && props.defaultValue.number !== undefined;
|
||||||
|
if (props.options && isSelected) {
|
||||||
|
isSelected = props.options.indexOf(props.defaultValue.number) > -1;
|
||||||
|
}
|
||||||
|
this.state = { isSelected };
|
||||||
|
this.onChangeNumber = this.onChangeNumber.bind(this);
|
||||||
|
this.onChangeNumberSet = this.onChangeNumberSet.bind(this);
|
||||||
|
this.onChangeComparator = this.onChangeComparator.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const comparator = this.numberFilterComparator.value;
|
||||||
|
const number = this.numberFilter.value;
|
||||||
|
if (comparator && number) {
|
||||||
|
onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeNumber(e) {
|
||||||
|
const { delay, column, onFilter } = this.props;
|
||||||
|
const comparator = this.numberFilterComparator.value;
|
||||||
|
if (comparator === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
const filterValue = e.target.value;
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
onFilter(column, { number: filterValue, comparator }, FILTER_TYPE.NUMBER);
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeNumberSet(e) {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const comparator = this.numberFilterComparator.value;
|
||||||
|
const { value } = e.target;
|
||||||
|
this.setState(() => ({ isSelected: (value !== '') }));
|
||||||
|
// if (comparator === '') {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeComparator(e) {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const value = this.numberFilter.value;
|
||||||
|
const comparator = e.target.value;
|
||||||
|
// if (value === '') {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
getComparatorOptions() {
|
||||||
|
const optionTags = [];
|
||||||
|
const { withoutEmptyComparatorOption } = this.props;
|
||||||
|
if (!withoutEmptyComparatorOption) {
|
||||||
|
optionTags.push(<option key="-1" />);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.comparators.length; i += 1) {
|
||||||
|
optionTags.push(
|
||||||
|
<option key={ i } value={ this.comparators[i] }>
|
||||||
|
{ this.comparators[i] }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return optionTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
getNumberOptions() {
|
||||||
|
const optionTags = [];
|
||||||
|
const { options, column, withoutEmptyNumberOption } = this.props;
|
||||||
|
if (!withoutEmptyNumberOption) {
|
||||||
|
optionTags.push(
|
||||||
|
<option key="-1" value="">
|
||||||
|
{ this.props.placeholder || `Select ${column.text}...` }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < options.length; i += 1) {
|
||||||
|
optionTags.push(<option key={ i } value={ options[i] }>{ options[i] }</option>);
|
||||||
|
}
|
||||||
|
return optionTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(filterObj) {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const { number, comparator } = filterObj;
|
||||||
|
this.setState(() => ({ isSelected: (number !== '') }));
|
||||||
|
this.numberFilterComparator.value = comparator;
|
||||||
|
this.numberFilter.value = number;
|
||||||
|
onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanFiltered() {
|
||||||
|
const { column, onFilter, defaultValue } = this.props;
|
||||||
|
const value = defaultValue ? defaultValue.number : '';
|
||||||
|
const comparator = defaultValue ? defaultValue.comparator : '';
|
||||||
|
this.setState(() => ({ isSelected: (value !== '') }));
|
||||||
|
this.numberFilterComparator.value = comparator;
|
||||||
|
this.numberFilter.value = value;
|
||||||
|
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isSelected } = this.state;
|
||||||
|
const {
|
||||||
|
defaultValue,
|
||||||
|
column,
|
||||||
|
options,
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
numberStyle,
|
||||||
|
numberClassName,
|
||||||
|
comparatorStyle,
|
||||||
|
comparatorClassName,
|
||||||
|
placeholder
|
||||||
|
} = this.props;
|
||||||
|
const selectClass = `
|
||||||
|
select-filter
|
||||||
|
number-filter-input
|
||||||
|
form-control
|
||||||
|
${numberClassName}
|
||||||
|
${!isSelected ? 'placeholder-selected' : ''}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ `filter number-filter ${className}` } style={ style }>
|
||||||
|
<select
|
||||||
|
ref={ n => this.numberFilterComparator = n }
|
||||||
|
style={ comparatorStyle }
|
||||||
|
className={ `number-filter-comparator form-control ${comparatorClassName}` }
|
||||||
|
onChange={ this.onChangeComparator }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.comparator : '' }
|
||||||
|
>
|
||||||
|
{ this.getComparatorOptions() }
|
||||||
|
</select>
|
||||||
|
{
|
||||||
|
options ?
|
||||||
|
<select
|
||||||
|
ref={ n => this.numberFilter = n }
|
||||||
|
style={ numberStyle }
|
||||||
|
className={ selectClass }
|
||||||
|
onChange={ this.onChangeNumberSet }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.number : '' }
|
||||||
|
>
|
||||||
|
{ this.getNumberOptions() }
|
||||||
|
</select> :
|
||||||
|
<input
|
||||||
|
ref={ n => this.numberFilter = n }
|
||||||
|
type="number"
|
||||||
|
style={ numberStyle }
|
||||||
|
className={ `number-filter-input form-control ${numberClassName}` }
|
||||||
|
placeholder={ placeholder || `Enter ${column.text}...` }
|
||||||
|
onChange={ this.onChangeNumber }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.number : '' }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberFilter.propTypes = {
|
||||||
|
onFilter: PropTypes.func.isRequired,
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
options: PropTypes.arrayOf(PropTypes.number),
|
||||||
|
defaultValue: PropTypes.shape({
|
||||||
|
number: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
comparator: PropTypes.oneOf([...legalComparators, ''])
|
||||||
|
}),
|
||||||
|
delay: PropTypes.number,
|
||||||
|
/* eslint consistent-return: 0 */
|
||||||
|
comparators: (props, propName) => {
|
||||||
|
if (!props[propName]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < props[propName].length; i += 1) {
|
||||||
|
let comparatorIsValid = false;
|
||||||
|
for (let j = 0; j < legalComparators.length; j += 1) {
|
||||||
|
if (legalComparators[j] === props[propName][i] || props[propName][i] === '') {
|
||||||
|
comparatorIsValid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!comparatorIsValid) {
|
||||||
|
return new Error(`Number comparator provided is not supported.
|
||||||
|
Use only ${legalComparators}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
withoutEmptyComparatorOption: PropTypes.bool,
|
||||||
|
withoutEmptyNumberOption: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
className: PropTypes.string,
|
||||||
|
comparatorStyle: PropTypes.object,
|
||||||
|
comparatorClassName: PropTypes.string,
|
||||||
|
numberStyle: PropTypes.object,
|
||||||
|
numberClassName: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberFilter.defaultProps = {
|
||||||
|
delay: FILTER_DELAY,
|
||||||
|
options: undefined,
|
||||||
|
defaultValue: {
|
||||||
|
number: undefined,
|
||||||
|
comparator: ''
|
||||||
|
},
|
||||||
|
withoutEmptyComparatorOption: false,
|
||||||
|
withoutEmptyNumberOption: false,
|
||||||
|
comparators: legalComparators,
|
||||||
|
placeholder: undefined,
|
||||||
|
style: undefined,
|
||||||
|
className: '',
|
||||||
|
comparatorStyle: undefined,
|
||||||
|
comparatorClassName: '',
|
||||||
|
numberStyle: undefined,
|
||||||
|
numberClassName: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NumberFilter;
|
||||||
@ -1,6 +1,7 @@
|
|||||||
export const FILTER_TYPE = {
|
export const FILTER_TYPE = {
|
||||||
TEXT: 'TEXT',
|
TEXT: 'TEXT',
|
||||||
SELECT: 'SELECT'
|
SELECT: 'SELECT',
|
||||||
|
NUMBER: 'NUMBER'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FILTER_DELAY = 500;
|
export const FILTER_DELAY = 500;
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
/* eslint eqeqeq: 0 */
|
||||||
|
/* eslint no-console: 0 */
|
||||||
import { FILTER_TYPE } from './const';
|
import { FILTER_TYPE } from './const';
|
||||||
import { LIKE, EQ } from './comparison';
|
import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison';
|
||||||
|
|
||||||
export const filterByText = _ => (
|
export const filterByText = _ => (
|
||||||
data,
|
data,
|
||||||
@ -19,12 +21,75 @@ export const filterByText = _ => (
|
|||||||
return cellStr.indexOf(filterVal) > -1;
|
return cellStr.indexOf(filterVal) > -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const filterByNumber = _ => (
|
||||||
|
data,
|
||||||
|
dataField,
|
||||||
|
{ filterVal: { comparator, number } },
|
||||||
|
customFilterValue
|
||||||
|
) =>
|
||||||
|
data.filter((row) => {
|
||||||
|
if (number === '' || !comparator) return true;
|
||||||
|
let valid = true;
|
||||||
|
let cell = _.get(row, dataField);
|
||||||
|
if (customFilterValue) {
|
||||||
|
cell = customFilterValue(cell, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (comparator) {
|
||||||
|
case EQ: {
|
||||||
|
if (cell != number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GT: {
|
||||||
|
if (cell <= number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GE: {
|
||||||
|
if (cell < number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LT: {
|
||||||
|
if (cell >= number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LE: {
|
||||||
|
if (cell > number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NE: {
|
||||||
|
if (cell == number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.error('Number comparator provided is not supported');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
});
|
||||||
|
|
||||||
export const filterFactory = _ => (filterType) => {
|
export const filterFactory = _ => (filterType) => {
|
||||||
let filterFn;
|
let filterFn;
|
||||||
switch (filterType) {
|
switch (filterType) {
|
||||||
case FILTER_TYPE.TEXT:
|
case FILTER_TYPE.TEXT:
|
||||||
|
case FILTER_TYPE.SELECT:
|
||||||
filterFn = filterByText(_);
|
filterFn = filterByText(_);
|
||||||
break;
|
break;
|
||||||
|
case FILTER_TYPE.NUMBER:
|
||||||
|
filterFn = filterByNumber(_);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
filterFn = filterByText(_);
|
filterFn = filterByText(_);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
|
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
|
||||||
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected {
|
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder {
|
||||||
color: lightgrey;
|
color: lightgrey;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@ -11,4 +13,19 @@
|
|||||||
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) {
|
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) {
|
||||||
color: initial;
|
color: initial;
|
||||||
font-style: initial;
|
font-style: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter-input {
|
||||||
|
margin-left: 5px;
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - 67px - 5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter-comparator {
|
||||||
|
width: 67px;
|
||||||
|
float: left;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user