This commit is contained in:
AllenFang 2019-08-10 13:45:02 +08:00
parent c53d2612d4
commit 4de565b759
11 changed files with 199 additions and 21 deletions

View File

@ -0,0 +1,94 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { ToggleList } = ColumnToggle;
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
sort: true,
filter: textFilter()
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
const { ToggleList } = ColumnToggle;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
sort: true,
filter: textFilter()
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
filter={ filterFactory() }
/>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<h3>Table will keep the filter/sort state when column toggle</h3>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
filter={ filterFactory() }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -210,6 +210,7 @@ import BasicColumnToggle from 'examples/column-toggle';
import DefaultVisibility from 'examples/column-toggle/default-visibility';
import StylingColumnToggle from 'examples/column-toggle/styling-toggle-list';
import CustomToggleList from 'examples/column-toggle/custom-toggle-list';
import ColumnToggleWithFilter from 'examples/column-toggle/column-toggle-with-filter';
// loading overlay
import EmptyTableOverlay from 'examples/loading-overlay/empty-table-overlay';
@ -451,7 +452,8 @@ storiesOf('Column Toggle', module)
.add('Basic Column Toggle', () => <BasicColumnToggle />)
.add('Default Visibility', () => <DefaultVisibility />)
.add('Styling Column Toggle', () => <StylingColumnToggle />)
.add('Custom Column Toggle', () => <CustomToggleList />);
.add('Custom Column Toggle', () => <CustomToggleList />)
.add('Column Toggle with Filter', () => <ColumnToggleWithFilter />);
storiesOf('Export CSV', module)
.addDecorator(bootstrapStyle())

View File

@ -83,14 +83,27 @@ class DateFilter extends Component {
return optionTags;
}
getDefaultDate() {
let defaultDate = '';
const { defaultValue } = this.props;
if (defaultValue && defaultValue.date) {
// Set the appropriate format for the input type=date, i.e. "YYYY-MM-DD"
defaultDate = dateParser(new Date(defaultValue.date));
getDefaultComparator() {
const { defaultValue, filterState } = this.props;
if (filterState && filterState.filterVal) {
return filterState.filterVal.comparator;
}
return defaultDate;
if (defaultValue && defaultValue.comparator) {
return defaultValue.comparator;
}
return '';
}
getDefaultDate() {
// Set the appropriate format for the input type=date, i.e. "YYYY-MM-DD"
const { defaultValue, filterState } = this.props;
if (filterState && filterState.filterVal && filterState.filterVal.date) {
return dateParser(filterState.filterVal.date);
}
if (defaultValue && defaultValue.date) {
return dateParser(new Date(defaultValue.date));
}
return '';
}
applyFilter(value, comparator, isInitial) {
@ -122,8 +135,7 @@ class DateFilter extends Component {
dateStyle,
className,
comparatorClassName,
dateClassName,
defaultValue
dateClassName
} = this.props;
return (
@ -143,7 +155,7 @@ class DateFilter extends Component {
style={ comparatorStyle }
className={ `date-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
defaultValue={ defaultValue ? defaultValue.comparator : '' }
defaultValue={ this.getDefaultComparator() }
>
{ this.getComparatorOptions() }
</select>
@ -169,6 +181,7 @@ class DateFilter extends Component {
DateFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
filterState: PropTypes.object,
delay: PropTypes.number,
defaultValue: PropTypes.shape({
date: PropTypes.oneOfType([PropTypes.object]),
@ -210,6 +223,7 @@ DateFilter.defaultProps = {
date: undefined,
comparator: ''
},
filterState: {},
withoutEmptyComparatorOption: false,
comparators: legalComparators,
placeholder: undefined,

View File

@ -69,6 +69,14 @@ class MultiSelectFilter extends Component {
}
}
getDefaultValue() {
const { filterState, defaultValue } = this.props;
if (filterState && typeof filterState.filterVal !== 'undefined') {
return filterState.filterVal;
}
return defaultValue;
}
getOptions() {
const optionTags = [];
const { options, placeholder, column, withoutEmptyOption } = this.props;
@ -106,6 +114,7 @@ class MultiSelectFilter extends Component {
const {
style,
className,
filterState,
defaultValue,
onFilter,
column,
@ -135,7 +144,7 @@ class MultiSelectFilter extends Component {
className={ selectClass }
onChange={ this.filter }
onClick={ e => e.stopPropagation() }
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
defaultValue={ this.getDefaultValue() }
>
{ this.getOptions() }
</select>
@ -148,6 +157,7 @@ MultiSelectFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
options: PropTypes.object.isRequired,
filterState: PropTypes.object,
comparator: PropTypes.oneOf([LIKE, EQ]),
placeholder: PropTypes.string,
style: PropTypes.object,
@ -160,6 +170,7 @@ MultiSelectFilter.propTypes = {
MultiSelectFilter.defaultProps = {
defaultValue: [],
filterState: {},
className: '',
withoutEmptyOption: false,
comparator: EQ,

View File

@ -94,6 +94,28 @@ class NumberFilter extends Component {
onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator });
}
getDefaultComparator() {
const { defaultValue, filterState } = this.props;
if (filterState && filterState.filterVal) {
return filterState.filterVal.comparator;
}
if (defaultValue && defaultValue.comparator) {
return defaultValue.comparator;
}
return '';
}
getDefaultValue() {
const { defaultValue, filterState } = this.props;
if (filterState && filterState.filterVal) {
return filterState.filterVal.number;
}
if (defaultValue && defaultValue.number) {
return defaultValue.number;
}
return '';
}
getComparatorOptions() {
const optionTags = [];
const { withoutEmptyComparatorOption } = this.props;
@ -148,7 +170,6 @@ class NumberFilter extends Component {
render() {
const { isSelected } = this.state;
const {
defaultValue,
column,
options,
style,
@ -184,7 +205,7 @@ class NumberFilter extends Component {
id={ `number-filter-comparator-${column.text}` }
className={ `number-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
defaultValue={ defaultValue ? defaultValue.comparator : '' }
defaultValue={ this.getDefaultComparator() }
>
{ this.getComparatorOptions() }
</select>
@ -202,7 +223,7 @@ class NumberFilter extends Component {
style={ numberStyle }
className={ selectClass }
onChange={ this.onChangeNumberSet }
defaultValue={ defaultValue ? defaultValue.number : '' }
defaultValue={ this.getDefaultValue() }
>
{ this.getNumberOptions() }
</select>
@ -217,7 +238,7 @@ class NumberFilter extends Component {
className={ `number-filter-input form-control ${numberClassName}` }
placeholder={ placeholder || `Enter ${column.text}...` }
onChange={ this.onChangeNumber }
defaultValue={ defaultValue ? defaultValue.number : '' }
defaultValue={ this.getDefaultValue() }
/>
</label>
}
@ -229,6 +250,7 @@ class NumberFilter extends Component {
NumberFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
filterState: PropTypes.object,
options: PropTypes.arrayOf(PropTypes.number),
defaultValue: PropTypes.shape({
number: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
@ -273,6 +295,7 @@ NumberFilter.defaultProps = {
number: undefined,
comparator: ''
},
filterState: {},
withoutEmptyComparatorOption: false,
withoutEmptyNumberOption: false,
comparators: legalComparators,

View File

@ -44,7 +44,7 @@ class SelectFilter extends Component {
constructor(props) {
super(props);
this.filter = this.filter.bind(this);
const isSelected = getOptionValue(props.options, props.defaultValue) !== undefined;
const isSelected = getOptionValue(props.options, this.getDefaultValue()) !== undefined;
this.state = { isSelected };
}
@ -82,6 +82,14 @@ class SelectFilter extends Component {
}
}
getDefaultValue() {
const { filterState, defaultValue } = this.props;
if (filterState && typeof filterState.filterVal !== 'undefined') {
return filterState.filterVal;
}
return defaultValue;
}
getOptions() {
const optionTags = [];
const { options, placeholder, column, withoutEmptyOption } = this.props;
@ -132,6 +140,7 @@ class SelectFilter extends Component {
withoutEmptyOption,
caseSensitive,
getFilter,
filterState,
...rest
} = this.props;
@ -152,7 +161,7 @@ class SelectFilter extends Component {
className={ selectClass }
onChange={ this.filter }
onClick={ e => e.stopPropagation() }
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
defaultValue={ this.getDefaultValue() || '' }
>
{ this.getOptions() }
</select>
@ -164,6 +173,7 @@ class SelectFilter extends Component {
SelectFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
filterState: PropTypes.object,
options: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
comparator: PropTypes.oneOf([LIKE, EQ]),
placeholder: PropTypes.string,
@ -177,6 +187,7 @@ SelectFilter.propTypes = {
SelectFilter.defaultProps = {
defaultValue: '',
filterState: {},
className: '',
withoutEmptyOption: false,
comparator: EQ,

View File

@ -13,8 +13,14 @@ class TextFilter extends Component {
this.filter = this.filter.bind(this);
this.handleClick = this.handleClick.bind(this);
this.timeout = null;
function getDefaultValue() {
if (props.filterState && typeof props.filterState.filterVal !== 'undefined') {
return props.filterState.filterVal;
}
return props.defaultValue;
}
this.state = {
value: props.defaultValue
value: getDefaultValue()
};
}
@ -89,6 +95,7 @@ class TextFilter extends Component {
caseSensitive,
defaultValue,
getFilter,
filterState,
...rest
} = this.props;
@ -119,6 +126,7 @@ class TextFilter extends Component {
TextFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
filterState: PropTypes.object,
comparator: PropTypes.oneOf([LIKE, EQ]),
defaultValue: PropTypes.string,
delay: PropTypes.number,
@ -131,6 +139,7 @@ TextFilter.propTypes = {
TextFilter.defaultProps = {
delay: FILTER_DELAY,
filterState: {},
defaultValue: '',
caseSensitive: false
};

View File

@ -108,7 +108,8 @@ export default (
<FilterContext.Provider value={ {
data: this.data,
onFilter: this.onFilter,
onExternalFilter: this.onExternalFilter
onExternalFilter: this.onExternalFilter,
currFilters: this.currFilters
} }
>
{ this.props.children }

View File

@ -91,6 +91,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
sortOrder={ this.props.sortOrder }
onSort={ this.props.onSort }
onFilter={ this.props.onFilter }
currFilters={ this.props.currFilters }
onExternalFilter={ this.props.onExternalFilter }
selectRow={ selectRow }
expandRow={ expandRow }

View File

@ -18,6 +18,7 @@ const HeaderCell = (props) => {
sortOrder,
isLastSorting,
onFilter,
currFilters,
onExternalFilter
} = props;
@ -99,7 +100,14 @@ const HeaderCell = (props) => {
const onCustomFilter = onExternalFilter(column, filter.props.type);
filterElm = filterRenderer(onCustomFilter, column);
} else if (filter) {
filterElm = <filter.Filter { ...filter.props } onFilter={ onFilter } column={ column } />;
filterElm = (
<filter.Filter
{ ...filter.props }
filterState={ currFilters[column.dataField] }
onFilter={ onFilter }
column={ column }
/>
);
}
const children = headerFormatter ?
@ -162,6 +170,7 @@ HeaderCell.propTypes = {
sortCaret: PropTypes.func,
isLastSorting: PropTypes.bool,
onFilter: PropTypes.func,
currFilters: PropTypes.object,
onExternalFilter: PropTypes.func
};

View File

@ -18,6 +18,7 @@ const Header = (props) => {
sortField,
sortOrder,
selectRow,
currFilters,
onExternalFilter,
expandRow
} = props;
@ -50,6 +51,7 @@ const Header = (props) => {
onSort={ onSort }
sorting={ currSort }
onFilter={ onFilter }
currFilters={ currFilters }
onExternalFilter={ onExternalFilter }
sortOrder={ sortOrder }
isLastSorting={ isLastSorting }
@ -89,6 +91,7 @@ Header.propTypes = {
sortField: PropTypes.string,
sortOrder: PropTypes.string,
selectRow: PropTypes.object,
currFilters: PropTypes.object,
onExternalFilter: PropTypes.func,
className: PropTypes.string,
expandRow: PropTypes.object