diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-filter-logic.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-filter-logic.js
new file mode 100644
index 0000000..906d9d0
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-filter-logic.js
@@ -0,0 +1,81 @@
+/* eslint eqeqeq: 0 */
+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);
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
+
+class Table extends React.Component {
+ filterByPrice = filterVal =>
+ products.filter(product => product.price == filterVal);
+
+ render() {
+ const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+ }, {
+ dataField: 'name',
+ text: 'Product Name',
+ filter: textFilter()
+ }, {
+ dataField: 'price',
+ text: 'Product Price',
+ filter: textFilter({
+ onFilter: this.filterByPrice
+ })
+ }];
+
+ return (
+
+
+
+ );
+ }
+}
+`;
+
+export default class Table extends React.Component {
+ filterByPrice = filterVal =>
+ products.filter(product => product.price == filterVal);
+
+ render() {
+ const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+ }, {
+ dataField: 'name',
+ text: 'Product Name',
+ filter: textFilter()
+ }, {
+ dataField: 'price',
+ text: 'Product Price',
+ filter: textFilter({
+ onFilter: this.filterByPrice
+ })
+ }];
+
+ return (
+
+
Implement a eq filter on product price column
+
+ { sourceCode }
+
+ );
+ }
+}
diff --git a/packages/react-bootstrap-table2-example/examples/pagination/custom-page-list-with-search.js b/packages/react-bootstrap-table2-example/examples/pagination/custom-page-list-with-search.js
new file mode 100644
index 0000000..87d5d74
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/pagination/custom-page-list-with-search.js
@@ -0,0 +1,139 @@
+/* eslint react/prefer-stateless-function: 0 */
+import React from 'react';
+
+import BootstrapTable from 'react-bootstrap-table-next';
+import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
+import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
+import Code from 'components/common/code-block';
+import { productsGenerator } from 'utils/common';
+
+const products = productsGenerator(21);
+const { SearchBar } = Search;
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}];
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
+import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
+
+class Table extends React.Component {
+ render() {
+ const options = {
+ custom: true,
+ paginationSize: 4,
+ pageStartIndex: 1,
+ firstPageText: 'First',
+ prePageText: 'Back',
+ nextPageText: 'Next',
+ lastPageText: 'Last',
+ nextPageTitle: 'First page',
+ prePageTitle: 'Pre page',
+ firstPageTitle: 'Next page',
+ lastPageTitle: 'Last page',
+ showTotal: true,
+ totalSize: products.length
+ };
+ const contentTable = ({ paginationProps, paginationTableProps }) => (
+
+ );
+
+ return (
+
+
PaginationProvider will care the data size change. You dont do anything
+
+ { contentTable }
+
+
{ sourceCode }
+
+ );
+ }
+}
+`;
+
+export default class Table extends React.Component {
+ render() {
+ const options = {
+ custom: true,
+ paginationSize: 4,
+ pageStartIndex: 1,
+ firstPageText: 'First',
+ prePageText: 'Back',
+ nextPageText: 'Next',
+ lastPageText: 'Last',
+ nextPageTitle: 'First page',
+ prePageTitle: 'Pre page',
+ firstPageTitle: 'Next page',
+ lastPageTitle: 'Last page',
+ showTotal: true,
+ totalSize: products.length
+ };
+ const contentTable = ({ paginationProps, paginationTableProps }) => (
+
+
+
+ {
+ toolkitprops => (
+
+
+
+
+ )
+ }
+
+
+
+ );
+
+ return (
+
+
PaginationProvider will care the data size change. You dont do anything
+
+ { contentTable }
+
+
{ sourceCode }
+
+ );
+ }
+}
diff --git a/packages/react-bootstrap-table2-example/examples/pagination/custome-page-list-with-filter.js b/packages/react-bootstrap-table2-example/examples/pagination/custome-page-list-with-filter.js
new file mode 100644
index 0000000..eefd780
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/pagination/custome-page-list-with-filter.js
@@ -0,0 +1,133 @@
+/* eslint react/prefer-stateless-function: 0 */
+import React from 'react';
+
+import BootstrapTable from 'react-bootstrap-table-next';
+import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
+import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
+import Code from 'components/common/code-block';
+import { productsGenerator } from 'utils/common';
+
+const products = productsGenerator(21);
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID',
+ filter: textFilter({})
+}, {
+ dataField: 'name',
+ text: 'Product Name',
+ filter: textFilter()
+}];
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
+import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
+
+class Table extends React.Component {
+ render() {
+ const options = {
+ custom: true,
+ paginationSize: 4,
+ pageStartIndex: 1,
+ firstPageText: 'First',
+ prePageText: 'Back',
+ nextPageText: 'Next',
+ lastPageText: 'Last',
+ nextPageTitle: 'First page',
+ prePageTitle: 'Pre page',
+ firstPageTitle: 'Next page',
+ lastPageTitle: 'Last page',
+ showTotal: true,
+ totalSize: products.length
+ };
+ const contentTable = ({ paginationProps, paginationTableProps }) => (
+
+ );
+
+ return (
+
+
PaginationProvider will care the data size change. You dont do anything
+
+ { contentTable }
+
+
{ sourceCode }
+
+ );
+ }
+}
+`;
+
+export default class Table extends React.Component {
+ render() {
+ const options = {
+ custom: true,
+ paginationSize: 4,
+ pageStartIndex: 1,
+ firstPageText: 'First',
+ prePageText: 'Back',
+ nextPageText: 'Next',
+ lastPageText: 'Last',
+ nextPageTitle: 'First page',
+ prePageTitle: 'Pre page',
+ firstPageTitle: 'Next page',
+ lastPageTitle: 'Last page',
+ showTotal: true,
+ totalSize: products.length
+ };
+ const contentTable = ({ paginationProps, paginationTableProps }) => (
+
+ );
+
+ return (
+
+
PaginationProvider will care the data size change. You dont do anything
+
+ { contentTable }
+
+
{ sourceCode }
+
+ );
+ }
+}
diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js
index 09ac547..a7ed50f 100644
--- a/packages/react-bootstrap-table2-example/stories/index.js
+++ b/packages/react-bootstrap-table2-example/stories/index.js
@@ -87,6 +87,7 @@ import CustomFilter from 'examples/column-filter/custom-filter';
import AdvanceCustomFilter from 'examples/column-filter/advance-custom-filter';
import ClearAllFilters from 'examples/column-filter/clear-all-filters';
import FilterHooks from 'examples/column-filter/filter-hooks';
+import CustomFilterLogic from 'examples/column-filter/custom-filter-logic';
// work on rows
import RowStyleTable from 'examples/rows/row-style';
@@ -169,6 +170,8 @@ import StandalonePaginationList from 'examples/pagination/standalone-pagination-
import StandaloneSizePerPage from 'examples/pagination/standalone-size-per-page';
import FullyCustomPaginationTable from 'examples/pagination/fully-custom-pagination';
import RemoteStandalonePaginationTable from 'examples/pagination/remote-standalone-pagination';
+import CustomePaginationWithFilter from 'examples/pagination/custome-page-list-with-filter';
+import CustomePaginationWithSearch from 'examples/pagination/custom-page-list-with-search';
// search
import SearchTable from 'examples/search';
@@ -289,7 +292,8 @@ storiesOf('Column Filter', module)
.add('Advance Custom Filter', () => )
.add('Preserved Option Order on Select Filter', () => )
.add('Clear All Filters', () => )
- .add('Filter Hooks', () => );
+ .add('Filter Hooks', () => )
+ .add('Implement custom filter logic', () => );
storiesOf('Work on Rows', module)
.addDecorator(bootstrapStyle())
@@ -390,7 +394,9 @@ storiesOf('Pagination', module)
.add('Standalone Pagination List', () => )
.add('Standalone SizePerPage Dropdown', () => )
.add('Fully Custom Pagination', () => )
- .add('Remote Fully Custom Pagination', () => );
+ .add('Remote Fully Custom Pagination', () => )
+ .add('Custom Pagination with Filter', () => )
+ .add('Custom Pagination with Search', () => );
storiesOf('Table Search', module)
.addDecorator(bootstrapStyle())
diff --git a/packages/react-bootstrap-table2-filter/src/context.js b/packages/react-bootstrap-table2-filter/src/context.js
index e82e53e..f3edd1f 100644
--- a/packages/react-bootstrap-table2-filter/src/context.js
+++ b/packages/react-bootstrap-table2-filter/src/context.js
@@ -17,7 +17,8 @@ export default (
class FilterProvider extends React.Component {
static propTypes = {
data: PropTypes.array.isRequired,
- columns: PropTypes.array.isRequired
+ columns: PropTypes.array.isRequired,
+ dataChangeListener: PropTypes.object
}
constructor(props) {
@@ -25,6 +26,9 @@ export default (
this.currFilters = {};
this.onFilter = this.onFilter.bind(this);
this.onExternalFilter = this.onExternalFilter.bind(this);
+ this.state = {
+ data: props.data
+ };
}
componentDidMount() {
@@ -33,6 +37,14 @@ export default (
}
}
+ componentWillReceiveProps(nextProps) {
+ if (isRemoteFiltering()) {
+ this.setState({
+ data: nextProps.data
+ });
+ }
+ }
+
onFilter(column, filterType, initialize = false) {
return (filterVal) => {
// watch out here if migration to context API, #334
@@ -64,11 +76,17 @@ export default (
return;
}
+ let result;
if (filter.props.onFilter) {
- filter.props.onFilter(filterVal);
+ result = filter.props.onFilter(filterVal);
}
- this.forceUpdate();
+ const { dataChangeListener, data } = this.props;
+ result = result || filters(data, this.props.columns, _)(this.currFilters);
+ if (dataChangeListener) {
+ dataChangeListener.emit('filterChanged', result.length);
+ }
+ this.setState({ data: result });
};
}
@@ -79,13 +97,9 @@ export default (
}
render() {
- let { data } = this.props;
- if (!isRemoteFiltering()) {
- data = filters(data, this.props.columns, _)(this.currFilters);
- }
return (
{
function shallowContext(
enableRemote = false,
- tableColumns = columns
+ tableColumns = columns,
+ dataChangeListener,
) {
mockBase.mockReset();
handleFilterChange.mockReset();
@@ -59,6 +60,7 @@ describe('FilterContext', () => {
{
@@ -252,6 +254,58 @@ describe('FilterContext', () => {
});
});
+ describe('if filter.props.onFilter is defined and return an undefined data', () => {
+ const mockReturn = [{
+ id: 1,
+ name: 'A'
+ }];
+ const filterVal = 'A';
+ const onFilter = jest.fn().mockReturnValue(mockReturn);
+ const customColumns = columns.map((column, i) => {
+ if (i === 1) {
+ return {
+ ...column,
+ filter: textFilter({ onFilter })
+ };
+ }
+ return column;
+ });
+
+ beforeEach(() => {
+ wrapper = shallow(shallowContext(false, customColumns));
+ wrapper.render();
+ instance = wrapper.instance();
+ });
+
+ it('should call filter.props.onFilter correctly', () => {
+ instance.onFilter(customColumns[1], FILTER_TYPE.TEXT)(filterVal);
+ expect(onFilter).toHaveBeenCalledTimes(1);
+ expect(onFilter).toHaveBeenCalledWith(filterVal);
+ });
+
+ it('should set state.data correctly', () => {
+ instance.onFilter(customColumns[1], FILTER_TYPE.TEXT)(filterVal);
+ expect(instance.state.data).toEqual(mockReturn);
+ });
+ });
+
+ describe('when props.dataChangeListener is defined', () => {
+ const filterVal = '3';
+ const newDataLength = 0;
+ const dataChangeListener = { emit: jest.fn() };
+
+ beforeEach(() => {
+ wrapper = shallow(shallowContext(false, columns, dataChangeListener));
+ wrapper.render();
+ instance = wrapper.instance();
+ });
+
+ it('should call dataChangeListener.emit correctly', () => {
+ instance.onFilter(columns[1], FILTER_TYPE.TEXT)(filterVal);
+ expect(dataChangeListener.emit).toHaveBeenCalledWith('filterChanged', newDataLength);
+ });
+ });
+
describe('combination', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
diff --git a/packages/react-bootstrap-table2-paginator/src/state-context.js b/packages/react-bootstrap-table2-paginator/src/state-context.js
index 758dd95..91159f6 100644
--- a/packages/react-bootstrap-table2-paginator/src/state-context.js
+++ b/packages/react-bootstrap-table2-paginator/src/state-context.js
@@ -2,7 +2,9 @@
/* eslint react/require-default-props: 0 */
/* eslint no-lonely-if: 0 */
import React from 'react';
+import EventEmitter from 'events';
import Const from './const';
+import { alignPage } from './page';
const StateContext = React.createContext();
@@ -10,6 +12,7 @@ class StateProvider extends React.Component {
constructor(props) {
super(props);
this.handleChangePage = this.handleChangePage.bind(this);
+ this.handleDataSizeChange = this.handleDataSizeChange.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
let currPage;
@@ -36,7 +39,10 @@ class StateProvider extends React.Component {
}
this.currPage = currPage;
+ this.dataSize = options.totalSize;
this.currSizePerPage = currSizePerPage;
+ this.dataChangeListener = new EventEmitter();
+ this.dataChangeListener.on('filterChanged', this.handleDataSizeChange);
}
componentWillReceiveProps(nextProps) {
@@ -46,12 +52,13 @@ class StateProvider extends React.Component {
if (this.isRemotePagination() || custom) {
this.currPage = nextProps.pagination.options.page;
this.currSizePerPage = nextProps.pagination.options.sizePerPage;
+ this.dataSize = nextProps.pagination.options.totalSize;
}
}
getPaginationProps = () => {
const { pagination: { options }, bootstrap4 } = this.props;
- const { currPage, currSizePerPage } = this;
+ const { currPage, currSizePerPage, dataSize } = this;
const withFirstAndLast = typeof options.withFirstAndLast === 'undefined' ?
Const.With_FIRST_AND_LAST : options.withFirstAndLast;
const alwaysShowAllBtns = typeof options.alwaysShowAllBtns === 'undefined' ?
@@ -72,7 +79,7 @@ class StateProvider extends React.Component {
hideSizePerPage,
alwaysShowAllBtns,
withFirstAndLast,
- dataSize: options.totalSize,
+ dataSize,
sizePerPageList: options.sizePerPageList || Const.SIZE_PER_PAGE_LIST,
paginationSize: options.paginationSize || Const.PAGINATION_SIZE,
showTotal: options.showTotal,
@@ -106,6 +113,20 @@ class StateProvider extends React.Component {
return e.result;
};
+ handleDataSizeChange(newDataSize) {
+ const { pagination: { options } } = this.props;
+ const pageStartIndex = typeof options.pageStartIndex === 'undefined' ?
+ Const.PAGE_START_INDEX : options.pageStartIndex;
+ this.dataSize = newDataSize;
+ this.currPage = alignPage(
+ newDataSize,
+ this.currPage,
+ this.currSizePerPage,
+ pageStartIndex
+ );
+ this.forceUpdate();
+ }
+
handleChangePage(currPage) {
const { currSizePerPage } = this;
const { pagination: { options } } = this.props;
@@ -153,7 +174,8 @@ class StateProvider extends React.Component {
paginationProps,
paginationTableProps: {
pagination,
- setPaginationRemoteEmitter: this.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: this.setPaginationRemoteEmitter,
+ dataChangeListener: this.dataChangeListener
}
} }
>
diff --git a/packages/react-bootstrap-table2-paginator/test/state-context.test.js b/packages/react-bootstrap-table2-paginator/test/state-context.test.js
index 828c667..bc4a91c 100644
--- a/packages/react-bootstrap-table2-paginator/test/state-context.test.js
+++ b/packages/react-bootstrap-table2-paginator/test/state-context.test.js
@@ -91,6 +91,10 @@ describe('PaginationStateContext', () => {
expect(wrapper.instance().currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]);
});
+ it('should have correct dataSize', () => {
+ expect(wrapper.instance().dataSize).toEqual(options.totalSize);
+ });
+
it('should get correct pagination props', () => {
const instance = wrapper.instance();
expect(wrapper.length).toBe(1);
@@ -102,7 +106,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -149,7 +154,7 @@ describe('PaginationStateContext', () => {
setRemotePaginationEmitter(instance, true);
nextProps = {
data,
- pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5 } }
+ pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5, totalSize: 50 } }
};
instance.componentWillReceiveProps(nextProps);
});
@@ -157,6 +162,7 @@ describe('PaginationStateContext', () => {
it('should always reset currPage and currSizePerPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
+ expect(instance.dataSize).toEqual(nextProps.pagination.options.totalSize);
});
});
@@ -170,7 +176,10 @@ describe('PaginationStateContext', () => {
setRemotePaginationEmitter(instance, true);
nextProps = {
data,
- pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5, custom: true } }
+ pagination: {
+ ...defaultPagination,
+ options: { page: 3, sizePerPage: 5, custom: true, totalSize: 50 }
+ }
};
instance.componentWillReceiveProps(nextProps);
});
@@ -178,10 +187,36 @@ describe('PaginationStateContext', () => {
it('should always reset currPage and currSizePerPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
+ expect(instance.dataSize).toEqual(nextProps.pagination.options.totalSize);
});
});
});
+ describe('handleDataSizeChange', () => {
+ let instance;
+ const newTotalSize = 8;
+ beforeEach(() => {
+ wrapper = shallow(shallowContext({
+ ...defaultPagination,
+ page: 3
+ }));
+ instance = wrapper.instance();
+ setRemotePaginationEmitter(instance);
+ jest.spyOn(instance, 'forceUpdate');
+ instance.handleDataSizeChange(newTotalSize);
+ });
+
+ it('should update dataSize correctly', () => {
+ expect(instance.dataSize).toEqual(newTotalSize);
+ expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
+ });
+
+ it('should update currPage correctly if page list shrink', () => {
+ expect(instance.currPage).toEqual(Const.PAGE_START_INDEX);
+ expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
+ });
+ });
+
describe('handleChangePage', () => {
let instance;
const newPage = 3;
@@ -343,7 +378,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -374,7 +410,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -401,7 +438,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -428,7 +466,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -455,7 +494,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -482,7 +522,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -509,7 +550,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -536,7 +578,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -563,7 +606,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -590,7 +634,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -617,7 +662,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -644,7 +690,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -671,7 +718,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -698,7 +746,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -725,7 +774,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -752,7 +802,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -779,7 +830,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -806,7 +858,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
@@ -833,7 +886,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
- setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
+ setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
+ dataChangeListener: expect.any(Object)
}
});
});
diff --git a/packages/react-bootstrap-table2-toolkit/src/search/context.js b/packages/react-bootstrap-table2-toolkit/src/search/context.js
index 90484bf..270a15d 100644
--- a/packages/react-bootstrap-table2-toolkit/src/search/context.js
+++ b/packages/react-bootstrap-table2-toolkit/src/search/context.js
@@ -1,6 +1,7 @@
/* eslint react/prop-types: 0 */
/* eslint react/require-default-props: 0 */
/* eslint no-continue: 0 */
+/* eslint no-lonely-if: 0 */
import React from 'react';
import PropTypes from 'prop-types';
@@ -17,36 +18,48 @@ export default (options = {
static propTypes = {
data: PropTypes.array.isRequired,
columns: PropTypes.array.isRequired,
- searchText: PropTypes.string
+ searchText: PropTypes.string,
+ dataChangeListener: PropTypes.object
}
constructor(props) {
super(props);
- this.performRemoteSearch = props.searchText !== '';
+ let initialData = props.data;
+ if (isRemoteSearch() && this.props.searchText !== '') {
+ handleRemoteSearchChange(this.props.searchText);
+ } else {
+ initialData = this.search(props.searchText.toLowerCase());
+ this.triggerListener(initialData);
+ }
+ this.state = { data: initialData };
}
componentWillReceiveProps(nextProps) {
- if (isRemoteSearch()) {
- if (nextProps.searchText !== this.props.searchText) {
- this.performRemoteSearch = true;
+ if (nextProps.searchText !== this.props.searchText) {
+ if (isRemoteSearch()) {
+ handleRemoteSearchChange(nextProps.searchText);
} else {
- this.performRemoteSearch = false;
+ const result = this.search(nextProps.searchText.toLowerCase());
+ this.triggerListener(result);
+ this.setState({
+ data: result
+ });
+ }
+ } else {
+ if (isRemoteSearch()) {
+ this.setState({ data: nextProps.data });
}
}
}
- search() {
- const { data, columns } = this.props;
- let { searchText } = this.props;
-
- if (isRemoteSearch()) {
- if (this.performRemoteSearch) {
- handleRemoteSearchChange(searchText);
- }
- return data;
+ triggerListener(result) {
+ if (this.props.dataChangeListener) {
+ this.props.dataChangeListener.emit('filterChanged', result.length);
}
+ }
- searchText = searchText.toLowerCase();
+ search(searchText) {
+ const { data, columns } = this.props;
return data.filter((row, ridx) => {
for (let cidx = 0; cidx < columns.length; cidx += 1) {
const column = columns[cidx];
@@ -69,9 +82,8 @@ export default (options = {
}
render() {
- const data = this.search();
return (
-
+
{ this.props.children }
);
diff --git a/packages/react-bootstrap-table2/src/body.js b/packages/react-bootstrap-table2/src/body.js
index a32a82e..2d445fc 100644
--- a/packages/react-bootstrap-table2/src/body.js
+++ b/packages/react-bootstrap-table2/src/body.js
@@ -15,9 +15,36 @@ import withRowExpansion from './row-expand/row-consumer';
class Body extends React.Component {
constructor(props) {
super(props);
- if (props.cellEdit.createContext) {
- this.EditingCell = props.cellEdit.createEditingCell(_, props.cellEdit.options.onStartEdit);
+ const {
+ keyField,
+ visibleColumnSize,
+ cellEdit,
+ selectRow,
+ expandRow
+ } = props;
+
+ // Construct Editing Cell Component
+ if (cellEdit.createContext) {
+ this.EditingCell = cellEdit.createEditingCell(_, cellEdit.options.onStartEdit);
}
+
+ // Construct Row Component
+ let RowComponent = SimpleRow;
+ const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
+ const expandRowEnabled = !!expandRow.renderer;
+
+ if (expandRowEnabled) {
+ RowComponent = withRowExpansion(RowAggregator, visibleColumnSize);
+ }
+
+ if (selectRowEnabled) {
+ RowComponent = withRowSelection(expandRowEnabled ? RowComponent : RowAggregator);
+ }
+
+ if (cellEdit.createContext) {
+ RowComponent = cellEdit.withRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _);
+ }
+ this.RowComponent = RowComponent;
}
render() {
@@ -46,21 +73,12 @@ class Body extends React.Component {
}
content = ;
} else {
- let RowComponent = SimpleRow;
const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
const expandRowEnabled = !!expandRow.renderer;
const additionalRowProps = {};
- if (expandRowEnabled) {
- RowComponent = withRowExpansion(RowAggregator, visibleColumnSize);
- }
-
- if (selectRowEnabled) {
- RowComponent = withRowSelection(expandRowEnabled ? RowComponent : RowAggregator);
- }
if (cellEdit.createContext) {
- RowComponent = cellEdit.withRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _);
additionalRowProps.EditingCellComponent = this.EditingCell;
}
@@ -88,7 +106,7 @@ class Body extends React.Component {
baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
- return ;
+ return ;
});
}
diff --git a/packages/react-bootstrap-table2/src/contexts/index.js b/packages/react-bootstrap-table2/src/contexts/index.js
index 7caf60c..4367ae1 100644
--- a/packages/react-bootstrap-table2/src/contexts/index.js
+++ b/packages/react-bootstrap-table2/src/contexts/index.js
@@ -217,6 +217,7 @@ const withContext = Base =>
ref={ n => this.searchContext = n }
data={ rootProps.getData(filterProps) }
searchText={ this.props.search.searchText }
+ dataChangeListener={ this.props.dataChangeListener }
>
{
@@ -237,6 +238,7 @@ const withContext = Base =>
{ ...baseProps }
ref={ n => this.filterContext = n }
data={ rootProps.getData() }
+ dataChangeListener={ this.props.dataChangeListener }
>
{