From f34cb4bf6353b48240afa9f97d64fbf0a23fd2b0 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Mon, 26 Mar 2018 23:49:27 +0800 Subject: [PATCH 01/12] allow user to filter column without inputField * wrap onFilter to HOF to allow filter dynamically --- .../src/wrapper.js | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/wrapper.js b/packages/react-bootstrap-table2-filter/src/wrapper.js index f48e031..9a64eb1 100644 --- a/packages/react-bootstrap-table2-filter/src/wrapper.js +++ b/packages/react-bootstrap-table2-filter/src/wrapper.js @@ -40,33 +40,42 @@ export default (Base, { } } - onFilter(column, filterVal, filterType) { - const { store, columns } = this.props; - const currFilters = Object.assign({}, this.state.currFilters); - const { dataField, filter } = column; + /** + * filter the table like below: + * onFilter(column, filterType)(filterVal) + * @param {Object} column + * @param {String} filterType + * @param {String} filterVal - user input for filtering. + */ + onFilter(column, filterType) { + return (filterVal) => { + const { store, columns } = this.props; + const currFilters = Object.assign({}, this.state.currFilters); + const { dataField, filter } = column; - if (!_.isDefined(filterVal) || filterVal === '') { - delete currFilters[dataField]; - } else { - // select default comparator is EQ, others are LIKE - const { - comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE), - caseSensitive = false - } = filter.props; - currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; - } - store.filters = currFilters; + if (!_.isDefined(filterVal) || filterVal === '') { + delete currFilters[dataField]; + } else { + // select default comparator is EQ, others are LIKE + const { + comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE), + caseSensitive = false + } = filter.props; + currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; + } + store.filters = currFilters; - if (this.isRemoteFiltering() || this.isRemotePagination()) { - this.handleRemoteFilterChange(); - // when remote filtering is enable, dont set currFilters state - // in the componentWillReceiveProps, - // it's the key point that we can know the filter is changed - return; - } + if (this.isRemoteFiltering() || this.isRemotePagination()) { + this.handleRemoteFilterChange(); + // when remote filtering is enable, dont set currFilters state + // in the componentWillReceiveProps, + // it's the key point that we can know the filter is changed + return; + } - store.filteredData = filters(store, columns, _)(currFilters); - this.setState(() => ({ currFilters, isDataChanged: true })); + store.filteredData = filters(store, columns, _)(currFilters); + this.setState(() => ({ currFilters, isDataChanged: true })); + }; } render() { From a1477e2ad38b29f66e9652634caa2d59ee5a6c18 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Tue, 27 Mar 2018 00:16:33 +0800 Subject: [PATCH 02/12] filter column by new onFilter --- .../src/components/number.js | 12 ++++++------ .../src/components/select.js | 10 +++++----- .../src/components/text.js | 13 +++++++++---- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index 3c2b612..5a99692 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -34,7 +34,7 @@ class NumberFilter extends Component { const comparator = this.numberFilterComparator.value; const number = this.numberFilter.value; if (comparator && number) { - onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator }); } } @@ -53,7 +53,7 @@ class NumberFilter extends Component { } const filterValue = e.target.value; this.timeout = setTimeout(() => { - onFilter(column, { number: filterValue, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: filterValue, comparator }); }, delay); } @@ -65,7 +65,7 @@ class NumberFilter extends Component { // if (comparator === '') { // return; // } - onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator }); } onChangeComparator(e) { @@ -75,7 +75,7 @@ class NumberFilter extends Component { // if (value === '') { // return; // } - onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator }); } getComparatorOptions() { @@ -116,7 +116,7 @@ class NumberFilter extends Component { this.setState(() => ({ isSelected: (number !== '') })); this.numberFilterComparator.value = comparator; this.numberFilter.value = number; - onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator }); } cleanFiltered() { @@ -126,7 +126,7 @@ class NumberFilter extends Component { this.setState(() => ({ isSelected: (value !== '') })); this.numberFilterComparator.value = comparator; this.numberFilter.value = value; - onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator }); } render() { diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 7e17afd..852938c 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -27,7 +27,7 @@ class SelectFilter extends Component { componentDidMount() { const value = this.selectInput.value; if (value && value !== '') { - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } } @@ -41,7 +41,7 @@ class SelectFilter extends Component { if (needFilter) { const value = this.selectInput.value; if (value) { - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } } } @@ -64,19 +64,19 @@ class SelectFilter extends Component { const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : ''; this.setState(() => ({ isSelected: value !== '' })); this.selectInput.value = value; - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } applyFilter(value) { this.selectInput.value = value; this.setState(() => ({ isSelected: value !== '' })); - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } filter(e) { const { value } = e.target; this.setState(() => ({ isSelected: value !== '' })); - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } render() { diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index ffbe702..154f308 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -17,10 +17,14 @@ class TextFilter extends Component { value: props.defaultValue }; } + componentDidMount() { + const { onFilter } = this.props; + const defaultValue = this.input.value; + if (defaultValue) { - this.props.onFilter(this.props.column, defaultValue, FILTER_TYPE.TEXT); + onFilter(this.props.column, FILTER_TYPE.TEXT)(defaultValue); } } @@ -40,7 +44,7 @@ class TextFilter extends Component { const filterValue = e.target.value; this.setState(() => ({ value: filterValue })); this.timeout = setTimeout(() => { - this.props.onFilter(this.props.column, filterValue, FILTER_TYPE.TEXT); + this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(filterValue); }, this.props.delay); } @@ -53,12 +57,12 @@ class TextFilter extends Component { cleanFiltered() { const value = this.props.defaultValue; this.setState(() => ({ value })); - this.props.onFilter(this.props.column, value, FILTER_TYPE.TEXT); + 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); + this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(filterText); } handleClick(e) { @@ -79,6 +83,7 @@ class TextFilter extends Component { defaultValue, ...rest } = this.props; + // stopPropagation for onClick event is try to prevent sort was triggered. return ( Date: Sun, 1 Apr 2018 13:51:11 +0800 Subject: [PATCH 03/12] export onFilter function to allow user to access --- .../src/components/number.js | 17 +++++++++++++++-- .../src/components/select.js | 16 ++++++++++++++-- .../src/components/text.js | 15 ++++++++++++--- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index 5a99692..3b946cf 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -1,3 +1,4 @@ +/* eslint react/require-default-props: 0 */ /* eslint no-return-assign: 0 */ import React, { Component } from 'react'; @@ -30,12 +31,23 @@ class NumberFilter extends Component { } componentDidMount() { - const { column, onFilter } = this.props; + const { column, onFilter, getFilterBy } = this.props; const comparator = this.numberFilterComparator.value; const number = this.numberFilter.value; if (comparator && number) { onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator }); } + + // export onFilter function to allow users to access + if (getFilterBy) { + getFilterBy((filterVal) => { + this.setState(() => ({ isSelected: (filterVal !== '') })); + onFilter(column, FILTER_TYPE.NUMBER)({ + number: filterVal.number, + comparator: filterVal.comparator + }); + }); + } } componentWillUnmount() { @@ -224,7 +236,8 @@ NumberFilter.propTypes = { comparatorStyle: PropTypes.object, comparatorClassName: PropTypes.string, numberStyle: PropTypes.object, - numberClassName: PropTypes.string + numberClassName: PropTypes.string, + getFilterBy: PropTypes.func }; NumberFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 852938c..8ba74b2 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -25,9 +25,19 @@ class SelectFilter extends Component { } componentDidMount() { + const { column, onFilter, getFilterBy } = this.props; + const value = this.selectInput.value; if (value && value !== '') { - this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); + onFilter(column, FILTER_TYPE.SELECT)(value); + } + + // export onFilter function to allow users to access + if (getFilterBy) { + getFilterBy((filterVal) => { + this.setState(() => ({ isSelected: filterVal !== '' })); + onFilter(column, FILTER_TYPE.SELECT)(filterVal); + }); } } @@ -90,6 +100,7 @@ class SelectFilter extends Component { comparator, withoutEmptyOption, caseSensitive, + getFilterBy, ...rest } = this.props; @@ -121,7 +132,8 @@ SelectFilter.propTypes = { className: PropTypes.string, withoutEmptyOption: PropTypes.bool, defaultValue: PropTypes.any, - caseSensitive: PropTypes.bool + caseSensitive: PropTypes.bool, + getFilterBy: PropTypes.func }; SelectFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index 154f308..65b6c7d 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -19,13 +19,20 @@ class TextFilter extends Component { } componentDidMount() { - const { onFilter } = this.props; - + const { onFilter, getFilterBy, column } = this.props; const defaultValue = this.input.value; if (defaultValue) { onFilter(this.props.column, FILTER_TYPE.TEXT)(defaultValue); } + + // export onFilter function to allow users to access + if (getFilterBy) { + getFilterBy((filterVal) => { + this.setState(() => ({ value: filterVal })); + onFilter(column, FILTER_TYPE.TEXT)(filterVal); + }); + } } componentWillReceiveProps(nextProps) { @@ -81,6 +88,7 @@ class TextFilter extends Component { onFilter, caseSensitive, defaultValue, + getFilterBy, ...rest } = this.props; @@ -110,7 +118,8 @@ TextFilter.propTypes = { placeholder: PropTypes.string, style: PropTypes.object, className: PropTypes.string, - caseSensitive: PropTypes.bool + caseSensitive: PropTypes.bool, + getFilterBy: PropTypes.func }; TextFilter.defaultProps = { From 09032349d0290365e307880b505350dc5467c616 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sun, 1 Apr 2018 14:49:22 +0800 Subject: [PATCH 04/12] [example] example for programmatically filter by text, number and select --- .../programmatically-number-filter.js | 85 ++++++++++++++++ .../programmatically-select-filter.js | 96 +++++++++++++++++++ .../programmatically-text-filter.js | 80 ++++++++++++++++ .../stories/index.js | 8 +- 4 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js new file mode 100644 index 0000000..76a26b8 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js @@ -0,0 +1,85 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + getFilterBy: (filterByFunc) => { + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy({ + number: 2103, + comparator: Comparator.GT + }); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + getFilterBy: (filterByFunc) => { + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy({ + number: 2103, + comparator: Comparator.GT + }); +}; + + + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js new file mode 100644 index 0000000..b084db2 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js @@ -0,0 +1,96 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsQualityGenerator } from 'utils/common'; + +const products = productsQualityGenerator(6); + +let filterBy; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + getFilterBy: (filterByFunc) => { + // filterBy was assigned to onFilter once the component has mount + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy('0'); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +let filterBy; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + getFilterBy: (filterByFunc) => { + // filterBy was assigned to onFilter once the component has mount + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy('0'); +}; + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js new file mode 100644 index 0000000..2e7f01b --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js @@ -0,0 +1,80 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + filter: textFilter({ + getFilterBy: (filterByFunc) => { + filterBy = filterByFunc; + } + }) +}, { + dataField: 'price', + text: 'Product Price', + filter: textFilter() +}]; + +const handleClick = () => { + filterBy('0'); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + filter: textFilter({ + getFilterBy: (filterByFunc) => { + // filterBy was assigned to onFilter once the component has mount + filterBy = filterByFunc; + } + }) +}, { + dataField: 'price', + text: 'Product Price', + filter: textFilter() +}]; + +const handleClick = () => { + filterBy('0'); +}; + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 25d8538..7e3ba5e 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -48,6 +48,9 @@ import CustomSelectFilter from 'examples/column-filter/custom-select-filter'; import NumberFilter from 'examples/column-filter/number-filter'; import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value'; import CustomNumberFilter from 'examples/column-filter/custom-number-filter'; +import ProgrammaticallyTextFilter from 'examples/column-filter/programmatically-text-filter'; +import ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter'; +import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter'; // work on rows import RowStyleTable from 'examples/rows/row-style'; @@ -166,7 +169,10 @@ storiesOf('Column Filter', module) .add('Custom Text Filter', () => ) .add('Custom Select Filter', () => ) .add('Custom Number Filter', () => ) - .add('Custom Filter Value', () => ); + .add('Custom Filter Value', () => ) + .add('Programmatically Text Filter ', () => ) + .add('Programmatically Select Filter ', () => ) + .add('Programmatically Number Filter ', () => ); storiesOf('Work on Rows', module) .add('Customize Row Style', () => ) From 377534512a35e0f850f9b91052c66db9cd04e3e9 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sun, 1 Apr 2018 15:59:26 +0800 Subject: [PATCH 05/12] rename props and variable in samples for better readability --- .../programmatically-number-filter.js | 22 +++++++++---------- .../programmatically-select-filter.js | 20 ++++++++--------- .../programmatically-text-filter.js | 19 ++++++++-------- .../src/components/number.js | 8 +++---- .../src/components/select.js | 10 ++++----- .../src/components/text.js | 10 ++++----- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js index 76a26b8..12a5ebc 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js @@ -6,7 +6,7 @@ import { productsGenerator } from 'utils/common'; const products = productsGenerator(8); -let filterBy; +let priceFilter; const columns = [{ dataField: 'id', @@ -18,14 +18,15 @@ const columns = [{ dataField: 'price', text: 'Product Price', filter: numberFilter({ - getFilterBy: (filterByFunc) => { - filterBy = filterByFunc; + getFilter: (filter) => { + // pricerFilter was assigned once the component has been mounted. + priceFilter = filter; } }) }]; const handleClick = () => { - filterBy({ + priceFilter({ number: 2103, comparator: Comparator.GT }); @@ -35,7 +36,7 @@ const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; -let filterBy; +let priceFilter; const columns = [{ dataField: 'id', @@ -47,24 +48,23 @@ const columns = [{ dataField: 'price', text: 'Product Price', filter: numberFilter({ - getFilterBy: (filterByFunc) => { - filterBy = filterByFunc; + getFilter: (filter) => { + // pricerFilter was assigned once the component has been mounted. + priceFilter = filter; } }) }]; const handleClick = () => { - filterBy({ + priceFilter({ number: 2103, comparator: Comparator.GT }); }; - - export default () => (
- +
diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js index b084db2..96f00de 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js @@ -6,7 +6,7 @@ import { productsQualityGenerator } from 'utils/common'; const products = productsQualityGenerator(6); -let filterBy; +let qualityFilter; const selectOptions = { 0: 'good', @@ -26,22 +26,22 @@ const columns = [{ formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, - getFilterBy: (filterByFunc) => { - // filterBy was assigned to onFilter once the component has mount - filterBy = filterByFunc; + getFilter: (filter) => { + // qualityFilter was assigned once the component has been mounted. + qualityFilter = filter; } }) }]; const handleClick = () => { - filterBy('0'); + qualityFilter('0'); }; const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; -let filterBy; +let qualityFilter; const selectOptions = { 0: 'good', @@ -61,15 +61,15 @@ const columns = [{ formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, - getFilterBy: (filterByFunc) => { - // filterBy was assigned to onFilter once the component has mount - filterBy = filterByFunc; + getFilter: (filter) => { + // qualityFilter was assigned once the component has been mounted. + qualityFilter = filter; } }) }]; const handleClick = () => { - filterBy('0'); + qualityFilter('0'); }; export default () => ( diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js index 2e7f01b..2db8698 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js @@ -6,7 +6,7 @@ import { productsGenerator } from 'utils/common'; const products = productsGenerator(8); -let filterBy; +let nameFilter; const columns = [{ dataField: 'id', @@ -15,8 +15,9 @@ const columns = [{ dataField: 'name', text: 'Product Name', filter: textFilter({ - getFilterBy: (filterByFunc) => { - filterBy = filterByFunc; + getFilter: (filter) => { + // nameFilter was assigned once the component has been mounted. + nameFilter = filter; } }) }, { @@ -26,14 +27,14 @@ const columns = [{ }]; const handleClick = () => { - filterBy('0'); + nameFilter('0'); }; const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; -let filterBy; +let nameFilter; const columns = [{ dataField: 'id', @@ -42,9 +43,9 @@ const columns = [{ dataField: 'name', text: 'Product Name', filter: textFilter({ - getFilterBy: (filterByFunc) => { - // filterBy was assigned to onFilter once the component has mount - filterBy = filterByFunc; + getFilter: (filter) => { + // nameFilter was assigned once the component has been mounted. + nameFilter = filter; } }) }, { @@ -54,7 +55,7 @@ const columns = [{ }]; const handleClick = () => { - filterBy('0'); + nameFilter('0'); }; export default () => ( diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index 3b946cf..c2d07ce 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -31,7 +31,7 @@ class NumberFilter extends Component { } componentDidMount() { - const { column, onFilter, getFilterBy } = this.props; + const { column, onFilter, getFilter } = this.props; const comparator = this.numberFilterComparator.value; const number = this.numberFilter.value; if (comparator && number) { @@ -39,8 +39,8 @@ class NumberFilter extends Component { } // export onFilter function to allow users to access - if (getFilterBy) { - getFilterBy((filterVal) => { + if (getFilter) { + getFilter((filterVal) => { this.setState(() => ({ isSelected: (filterVal !== '') })); onFilter(column, FILTER_TYPE.NUMBER)({ number: filterVal.number, @@ -237,7 +237,7 @@ NumberFilter.propTypes = { comparatorClassName: PropTypes.string, numberStyle: PropTypes.object, numberClassName: PropTypes.string, - getFilterBy: PropTypes.func + getFilter: PropTypes.func }; NumberFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 8ba74b2..91ab934 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -25,7 +25,7 @@ class SelectFilter extends Component { } componentDidMount() { - const { column, onFilter, getFilterBy } = this.props; + const { column, onFilter, getFilter } = this.props; const value = this.selectInput.value; if (value && value !== '') { @@ -33,8 +33,8 @@ class SelectFilter extends Component { } // export onFilter function to allow users to access - if (getFilterBy) { - getFilterBy((filterVal) => { + if (getFilter) { + getFilter((filterVal) => { this.setState(() => ({ isSelected: filterVal !== '' })); onFilter(column, FILTER_TYPE.SELECT)(filterVal); }); @@ -100,7 +100,7 @@ class SelectFilter extends Component { comparator, withoutEmptyOption, caseSensitive, - getFilterBy, + getFilter, ...rest } = this.props; @@ -133,7 +133,7 @@ SelectFilter.propTypes = { withoutEmptyOption: PropTypes.bool, defaultValue: PropTypes.any, caseSensitive: PropTypes.bool, - getFilterBy: PropTypes.func + getFilter: PropTypes.func }; SelectFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index 65b6c7d..7468044 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -19,7 +19,7 @@ class TextFilter extends Component { } componentDidMount() { - const { onFilter, getFilterBy, column } = this.props; + const { onFilter, getFilter, column } = this.props; const defaultValue = this.input.value; if (defaultValue) { @@ -27,8 +27,8 @@ class TextFilter extends Component { } // export onFilter function to allow users to access - if (getFilterBy) { - getFilterBy((filterVal) => { + if (getFilter) { + getFilter((filterVal) => { this.setState(() => ({ value: filterVal })); onFilter(column, FILTER_TYPE.TEXT)(filterVal); }); @@ -88,7 +88,7 @@ class TextFilter extends Component { onFilter, caseSensitive, defaultValue, - getFilterBy, + getFilter, ...rest } = this.props; @@ -119,7 +119,7 @@ TextFilter.propTypes = { style: PropTypes.object, className: PropTypes.string, caseSensitive: PropTypes.bool, - getFilterBy: PropTypes.func + getFilter: PropTypes.func }; TextFilter.defaultProps = { From f54c1f77b41720953afbb0476ea1a52700f8f95e Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Wed, 4 Apr 2018 15:39:23 +0800 Subject: [PATCH 06/12] display filter condition correctly and make sure text filter to be String --- .../programmatically-select-filter.js | 8 ++-- .../programmatically-text-filter.js | 4 +- .../src/components/number.js | 3 ++ .../src/components/select.js | 2 + .../src/filter.js | 44 +++++++++++-------- .../src/wrapper.js | 1 + 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js index 96f00de..d368af5 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js @@ -22,7 +22,7 @@ const columns = [{ text: 'Product Name' }, { dataField: 'quality', - text: 'Product Quailty', + text: 'Product Quality', formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, @@ -34,7 +34,7 @@ const columns = [{ }]; const handleClick = () => { - qualityFilter('0'); + qualityFilter(0); }; const sourceCode = `\ @@ -57,7 +57,7 @@ const columns = [{ text: 'Product Name' }, { dataField: 'quality', - text: 'Product Quailty', + text: 'Product Quality', formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, @@ -69,7 +69,7 @@ const columns = [{ }]; const handleClick = () => { - qualityFilter('0'); + qualityFilter(0); }; export default () => ( diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js index 2db8698..f1080c0 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js @@ -27,7 +27,7 @@ const columns = [{ }]; const handleClick = () => { - nameFilter('0'); + nameFilter(0); }; const sourceCode = `\ @@ -55,7 +55,7 @@ const columns = [{ }]; const handleClick = () => { - nameFilter('0'); + nameFilter(0); }; export default () => ( diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index c2d07ce..ebf55e8 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -42,6 +42,9 @@ class NumberFilter extends Component { if (getFilter) { getFilter((filterVal) => { this.setState(() => ({ isSelected: (filterVal !== '') })); + this.numberFilterComparator.value = filterVal.comparator; + this.numberFilter.value = filterVal.number; + onFilter(column, FILTER_TYPE.NUMBER)({ number: filterVal.number, comparator: filterVal.comparator diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 91ab934..ba2d306 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -36,6 +36,8 @@ class SelectFilter extends Component { if (getFilter) { getFilter((filterVal) => { this.setState(() => ({ isSelected: filterVal !== '' })); + this.selectInput.value = filterVal; + onFilter(column, FILTER_TYPE.SELECT)(filterVal); }); } diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index e0d7a45..9f7812c 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -6,30 +6,37 @@ import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison'; export const filterByText = _ => ( data, dataField, - { filterVal = '', comparator = LIKE, caseSensitive }, + { filterVal: userInput = '', comparator = LIKE, caseSensitive }, customFilterValue -) => - data.filter((row) => { - let cell = _.get(row, dataField); - if (customFilterValue) { - cell = customFilterValue(cell, row); - } - const cellStr = _.isDefined(cell) ? cell.toString() : ''; - if (comparator === EQ) { - return cellStr === filterVal; - } - if (caseSensitive) { - return cellStr.includes(filterVal); - } - return cellStr.toLocaleUpperCase().indexOf(filterVal.toLocaleUpperCase()) !== -1; - }); +) => { + // make sure filter value to be a string + const filterVal = userInput.toString(); + + return ( + data.filter((row) => { + let cell = _.get(row, dataField); + if (customFilterValue) { + cell = customFilterValue(cell, row); + } + const cellStr = _.isDefined(cell) ? cell.toString() : ''; + if (comparator === EQ) { + return cellStr === filterVal; + } + if (caseSensitive) { + return cellStr.includes(filterVal); + } + + return cellStr.toLocaleUpperCase().indexOf(filterVal.toLocaleUpperCase()) !== -1; + }) + ); +}; export const filterByNumber = _ => ( data, dataField, { filterVal: { comparator, number } }, customFilterValue -) => +) => ( data.filter((row) => { if (number === '' || !comparator) return true; let valid = true; @@ -81,7 +88,8 @@ export const filterByNumber = _ => ( } } return valid; - }); + }) +); export const filterFactory = _ => (filterType) => { let filterFn; diff --git a/packages/react-bootstrap-table2-filter/src/wrapper.js b/packages/react-bootstrap-table2-filter/src/wrapper.js index 9a64eb1..f13e615 100644 --- a/packages/react-bootstrap-table2-filter/src/wrapper.js +++ b/packages/react-bootstrap-table2-filter/src/wrapper.js @@ -63,6 +63,7 @@ export default (Base, { } = filter.props; currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; } + store.filters = currFilters; if (this.isRemoteFiltering() || this.isRemotePagination()) { From a35701fabfc84675656a1f81fed1ba7c1c59116d Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Wed, 4 Apr 2018 16:23:59 +0800 Subject: [PATCH 07/12] [test] correct test for filter wrapper --- .../test/filter.test.js | 13 ++++++++++++ .../test/wrapper.test.js | 20 +++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/test/filter.test.js b/packages/react-bootstrap-table2-filter/test/filter.test.js index ae66a38..2ffd36d 100644 --- a/packages/react-bootstrap-table2-filter/test/filter.test.js +++ b/packages/react-bootstrap-table2-filter/test/filter.test.js @@ -42,6 +42,19 @@ describe('filter', () => { filterFn = filters(store, columns, _); }); + describe('when filter value is not a String', () => { + it('should transform to string and do the filter', () => { + currFilters.name = { + filterVal: 3, + filterType: FILTER_TYPE.TEXT + }; + + const result = filterFn(currFilters); + expect(result).toBeDefined(); + expect(result).toHaveLength(2); + }); + }); + describe(`when default comparator is ${LIKE}`, () => { it('should returning correct result', () => { currFilters.name = { diff --git a/packages/react-bootstrap-table2-filter/test/wrapper.test.js b/packages/react-bootstrap-table2-filter/test/wrapper.test.js index 3d86285..1442658 100644 --- a/packages/react-bootstrap-table2-filter/test/wrapper.test.js +++ b/packages/react-bootstrap-table2-filter/test/wrapper.test.js @@ -167,14 +167,14 @@ describe('Wrapper', () => { it('should setting store object correctly', () => { filterVals.forEach((filterVal) => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(props.store.filtering).toBeFalsy(); }); }); it('should setting state correctly', () => { filterVals.forEach((filterVal) => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(0); }); @@ -185,12 +185,12 @@ describe('Wrapper', () => { const filterVal = '3'; it('should setting store object correctly', () => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(props.store.filters).toEqual(instance.state.currFilters); }); it('should setting state correctly', () => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); }); @@ -203,7 +203,7 @@ describe('Wrapper', () => { props = createTableProps(); props.remote = { filter: true }; createFilterWrapper(props); - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); }); it('should not setting store object correctly', () => { @@ -222,27 +222,27 @@ describe('Wrapper', () => { describe('combination', () => { it('should setting store object correctly', () => { - instance.onFilter(props.columns[1], '3', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('3'); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); - instance.onFilter(props.columns[1], '2', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('2'); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); - instance.onFilter(props.columns[2], '2', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[2], FILTER_TYPE.TEXT)('2'); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(2); - instance.onFilter(props.columns[2], '', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[2], FILTER_TYPE.TEXT)(''); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); - instance.onFilter(props.columns[1], '', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(''); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(0); From c64951fd6fb8d710c6018431420a4620943bc2ea Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Wed, 4 Apr 2018 16:51:54 +0800 Subject: [PATCH 08/12] [test] correct tests for filter components * ,