Compare commits

...

16 Commits

Author SHA1 Message Date
AllenFang
8e142de332 Publish
- react-bootstrap-table2-example@1.0.17
 - react-bootstrap-table2-filter@1.1.4
 - react-bootstrap-table2-toolkit@1.2.2
 - react-bootstrap-table-next@2.1.2
2019-02-16 17:11:10 +08:00
Allen
322605f14e Merge pull request #798 from react-bootstrap-table/develop
20190216 release
2019-02-16 17:09:40 +08:00
Allen
3156e01dd6 fix #788 (#797) 2019-02-16 16:26:26 +08:00
Allen
052284a163 fix #791 (#796) 2019-02-16 16:18:33 +08:00
AllenFang
3cd8efffb9 Publish
- react-bootstrap-table2-example@1.0.16
 - react-bootstrap-table2-filter@1.1.3
 - react-bootstrap-table2-paginator@2.0.2
 - react-bootstrap-table2-toolkit@1.2.1
 - react-bootstrap-table-next@2.1.1
2019-02-09 21:07:26 +08:00
Allen
447d69cae5 Merge pull request #790 from react-bootstrap-table/develop
20190209 release
2019-02-09 21:04:28 +08:00
AllenFang
cacc28e1bc fix test cases 2019-02-09 20:28:28 +08:00
AllenFang
d7f84a9da5 fix remote filter/search broken when pagination enabled 2019-02-09 18:01:53 +08:00
AllenFang
63c2630f46 fix same issue #778, but for search 2019-02-07 15:44:15 +08:00
AllenFang
903dd2e5c8 rename listenerForPagination -> dataChangeListener 2019-02-07 15:34:03 +08:00
AllenFang
964faa53e3 fix wrong storyb code 2019-02-07 13:56:42 +08:00
AllenFang
8fb5364cc2 add story for #445 2019-02-06 22:56:53 +08:00
AllenFang
8b89b3de0e fix #445 2019-02-06 22:56:31 +08:00
AllenFang
4506a3dea2 add story for #778 2019-02-06 18:06:08 +08:00
AllenFang
ecea3efdaa fix #778 2019-02-06 18:05:53 +08:00
AllenFang
8bef7eb348 fix #672 2019-02-06 15:15:26 +08:00
24 changed files with 1118 additions and 92 deletions

View File

@@ -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 (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
</div>
);
}
}
`;
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 (
<div>
<h2>Implement a eq filter on product price column</h2>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -0,0 +1,70 @@
/* 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 { productsGenerator } from 'utils/common';
const ProductList = (props) => {
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name',
filter: textFilter({
defaultValue: '1'
})
},
{
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}
];
return (
<div style={ { paddingTop: '20px' } }>
<h1 className="h2">Products</h1>
<BootstrapTable
keyField="id"
data={ props.products }
columns={ columns }
filter={ filterFactory() }
/>
</div>
);
};
export default class DataContainer extends React.Component {
state = {
products: productsGenerator(3)
};
loadData = () => {
this.setState({
products: productsGenerator(14)
});
}
render() {
return (
<div>
<button
onClick={ this.loadData }
style={ {
fontSize: '20px',
position: 'absolute',
left: '200px',
top: '40px'
} }
>
Load Data
</button>
<ProductList products={ this.state.products } />
</div>
);
}
}

View File

@@ -0,0 +1,80 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
import { productsGenerator } from 'utils/common';
const { SearchBar } = Search;
const ProductList = (props) => {
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
}
];
return (
<div style={ { paddingTop: '20px' } }>
<h1 className="h2">Products</h1>
<ToolkitProvider
keyField="id"
data={ props.products }
columns={ columns }
search={ { defaultSearch: '2101' } }
>
{
toolkitprops => (
<div>
<SearchBar { ...toolkitprops.searchProps } />
<BootstrapTable
striped
hover
{ ...toolkitprops.baseProps }
/>
</div>
)
}
</ToolkitProvider>
</div>
);
};
export default class DataContainer extends React.Component {
state = {
products: productsGenerator(3)
};
loadData = () => {
this.setState({
products: productsGenerator(14)
});
}
render() {
return (
<div>
<button
onClick={ this.loadData }
style={ {
fontSize: '20px',
position: 'absolute',
left: '200px',
top: '40px'
} }
>
Load Data
</button>
<ProductList products={ this.state.products } />
</div>
);
}
}

View File

@@ -0,0 +1,68 @@
/* 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 { productsGenerator } from 'utils/common';
const ProductList = (props) => {
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name',
filter: textFilter()
},
{
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}
];
return (
<div style={ { paddingTop: '20px' } }>
<h1 className="h2">Products</h1>
<BootstrapTable
keyField="id"
data={ props.products }
columns={ columns }
filter={ filterFactory() }
/>
</div>
);
};
export default class DataContainer extends React.Component {
state = {
products: []
};
loadData = () => {
this.setState({
products: productsGenerator()
});
}
render() {
return (
<div>
<button
onClick={ this.loadData }
style={ {
fontSize: '20px',
position: 'absolute',
left: '200px',
top: '40px'
} }
>
Load Data
</button>
<ProductList products={ this.state.products } />
</div>
);
}
}

View File

@@ -0,0 +1,72 @@
/* 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 paginationFactory from 'react-bootstrap-table2-paginator';
import { productsGenerator } from 'utils/common';
const ProductList = (props) => {
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name',
filter: textFilter({
defaultValue: '6'
})
},
{
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}
];
return (
<div style={ { paddingTop: '20px' } }>
<h1 className="h2">Products</h1>
<BootstrapTable
keyField="id"
data={ props.products }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory() }
/>
</div>
);
};
export default class DataContainer extends React.Component {
state = {
products: productsGenerator(60)
};
loadData = () => {
this.setState({
products: productsGenerator(14)
});
}
render() {
return (
<div>
<button
onClick={ this.loadData }
style={ {
fontSize: '20px',
position: 'absolute',
left: '200px',
top: '40px'
} }
>
Load Data
</button>
<ProductList products={ this.state.products } />
</div>
);
}
}

View File

@@ -0,0 +1,80 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
import { productsGenerator } from 'utils/common';
const { SearchBar } = Search;
const ProductList = (props) => {
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
}
];
return (
<div style={ { paddingTop: '20px' } }>
<h1 className="h2">Products</h1>
<ToolkitProvider
keyField="id"
data={ props.products }
columns={ columns }
search
>
{
toolkitprops => (
<div>
<SearchBar { ...toolkitprops.searchProps } />
<BootstrapTable
striped
hover
{ ...toolkitprops.baseProps }
/>
</div>
)
}
</ToolkitProvider>
</div>
);
};
export default class DataContainer extends React.Component {
state = {
products: []
};
loadData = () => {
this.setState({
products: productsGenerator()
});
}
render() {
return (
<div>
<button
onClick={ this.loadData }
style={ {
fontSize: '20px',
position: 'absolute',
left: '200px',
top: '40px'
} }
>
Load Data
</button>
<ProductList products={ this.state.products } />
</div>
);
}
}

View File

@@ -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 }) => (
<div>
<PaginationListStandalone { ...paginationProps } />
<div>
<div>
<BootstrapTable
striped
hover
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
cellEdit={ cellEditFactory() }
{ ...paginationTableProps }
/>
</div>
</div>
<PaginationListStandalone { ...paginationProps } />
</div>
);
return (
<div>
<h2>PaginationProvider will care the data size change. You dont do anything</h2>
<PaginationProvider
pagination={
paginationFactory(options)
}
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
}
`;
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 }) => (
<div>
<PaginationListStandalone { ...paginationProps } />
<ToolkitProvider
keyField="id"
columns={ columns }
data={ products }
search
>
{
toolkitprops => (
<div>
<SearchBar { ...toolkitprops.searchProps } />
<BootstrapTable
striped
hover
{ ...toolkitprops.baseProps }
{ ...paginationTableProps }
/>
</div>
)
}
</ToolkitProvider>
<PaginationListStandalone { ...paginationProps } />
</div>
);
return (
<div>
<h2>PaginationProvider will care the data size change. You dont do anything</h2>
<PaginationProvider
pagination={
paginationFactory(options)
}
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
}

View File

@@ -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 }) => (
<div>
<PaginationListStandalone { ...paginationProps } />
<div>
<div>
<BootstrapTable
striped
hover
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
cellEdit={ cellEditFactory() }
{ ...paginationTableProps }
/>
</div>
</div>
<PaginationListStandalone { ...paginationProps } />
</div>
);
return (
<div>
<h2>PaginationProvider will care the data size change. You dont do anything</h2>
<PaginationProvider
pagination={
paginationFactory(options)
}
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
}
`;
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 }) => (
<div>
<PaginationListStandalone { ...paginationProps } />
<div>
<div>
<BootstrapTable
striped
hover
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
{ ...paginationTableProps }
/>
</div>
</div>
<PaginationListStandalone { ...paginationProps } />
</div>
);
return (
<div>
<h2>PaginationProvider will care the data size change. You dont do anything</h2>
<PaginationProvider
pagination={
paginationFactory(options)
}
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-example", "name": "react-bootstrap-table2-example",
"version": "1.0.15", "version": "1.0.17",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true, "private": true,

View File

@@ -87,6 +87,7 @@ import CustomFilter from 'examples/column-filter/custom-filter';
import AdvanceCustomFilter from 'examples/column-filter/advance-custom-filter'; import AdvanceCustomFilter from 'examples/column-filter/advance-custom-filter';
import ClearAllFilters from 'examples/column-filter/clear-all-filters'; import ClearAllFilters from 'examples/column-filter/clear-all-filters';
import FilterHooks from 'examples/column-filter/filter-hooks'; import FilterHooks from 'examples/column-filter/filter-hooks';
import CustomFilterLogic from 'examples/column-filter/custom-filter-logic';
// work on rows // work on rows
import RowStyleTable from 'examples/rows/row-style'; 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 StandaloneSizePerPage from 'examples/pagination/standalone-size-per-page';
import FullyCustomPaginationTable from 'examples/pagination/fully-custom-pagination'; import FullyCustomPaginationTable from 'examples/pagination/fully-custom-pagination';
import RemoteStandalonePaginationTable from 'examples/pagination/remote-standalone-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 // search
import SearchTable from 'examples/search'; import SearchTable from 'examples/search';
@@ -202,6 +205,13 @@ import RemoteSearch from 'examples/remote/remote-search';
import RemoteCellEdit from 'examples/remote/remote-celledit'; import RemoteCellEdit from 'examples/remote/remote-celledit';
import RemoteAll from 'examples/remote/remote-all'; import RemoteAll from 'examples/remote/remote-all';
// data
import LoadDataWithFilter from 'examples/data/load-data-on-the-fly-with-filter';
import LoadDataWithDefaultFilter from 'examples/data/load-data-on-the-fly-with-default-filter';
import LoadDataWithSearch from 'examples/data/load-data-on-the-fly-with-search';
import LoadDataWithDefaultSearch from 'examples/data/load-data-on-the-fly-with-default-search';
import LoadDataWithPaginationAndFilter from 'examples/data/load-data-on-the-fly-with-pagination-and-filter';
// css style // css style
import 'stories/stylesheet/tomorrow.min.css'; import 'stories/stylesheet/tomorrow.min.css';
import 'stories/stylesheet/storybook.scss'; import 'stories/stylesheet/storybook.scss';
@@ -289,7 +299,8 @@ storiesOf('Column Filter', module)
.add('Advance Custom Filter', () => <AdvanceCustomFilter />) .add('Advance Custom Filter', () => <AdvanceCustomFilter />)
.add('Preserved Option Order on Select Filter', () => <SelectFilterWithPreservedOptionsOrder />) .add('Preserved Option Order on Select Filter', () => <SelectFilterWithPreservedOptionsOrder />)
.add('Clear All Filters', () => <ClearAllFilters />) .add('Clear All Filters', () => <ClearAllFilters />)
.add('Filter Hooks', () => <FilterHooks />); .add('Filter Hooks', () => <FilterHooks />)
.add('Implement custom filter logic', () => <CustomFilterLogic />);
storiesOf('Work on Rows', module) storiesOf('Work on Rows', module)
.addDecorator(bootstrapStyle()) .addDecorator(bootstrapStyle())
@@ -390,7 +401,9 @@ storiesOf('Pagination', module)
.add('Standalone Pagination List', () => <StandalonePaginationList />) .add('Standalone Pagination List', () => <StandalonePaginationList />)
.add('Standalone SizePerPage Dropdown', () => <StandaloneSizePerPage />) .add('Standalone SizePerPage Dropdown', () => <StandaloneSizePerPage />)
.add('Fully Custom Pagination', () => <FullyCustomPaginationTable />) .add('Fully Custom Pagination', () => <FullyCustomPaginationTable />)
.add('Remote Fully Custom Pagination', () => <RemoteStandalonePaginationTable />); .add('Remote Fully Custom Pagination', () => <RemoteStandalonePaginationTable />)
.add('Custom Pagination with Filter', () => <CustomePaginationWithFilter />)
.add('Custom Pagination with Search', () => <CustomePaginationWithSearch />);
storiesOf('Table Search', module) storiesOf('Table Search', module)
.addDecorator(bootstrapStyle()) .addDecorator(bootstrapStyle())
@@ -427,3 +440,11 @@ storiesOf('Remote', module)
.add('Remote Search', () => <RemoteSearch />) .add('Remote Search', () => <RemoteSearch />)
.add('Remote Cell Editing', () => <RemoteCellEdit />) .add('Remote Cell Editing', () => <RemoteCellEdit />)
.add('Remote All', () => <RemoteAll />); .add('Remote All', () => <RemoteAll />);
storiesOf('Data', module)
.addDecorator(bootstrapStyle())
.add('Load data with Filter', () => <LoadDataWithFilter />)
.add('Load data with Default Filter', () => <LoadDataWithDefaultFilter />)
.add('Load data with Search', () => <LoadDataWithSearch />)
.add('Load data with Default Search', () => <LoadDataWithDefaultSearch />)
.add('Load data with Filter and Pagination', () => <LoadDataWithPaginationAndFilter />);

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-filter", "name": "react-bootstrap-table2-filter",
"version": "1.1.2", "version": "1.1.4",
"description": "it's a column filter addon for react-bootstrap-table2", "description": "it's a column filter addon for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -17,14 +17,19 @@ export default (
class FilterProvider extends React.Component { class FilterProvider extends React.Component {
static propTypes = { static propTypes = {
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
columns: PropTypes.array.isRequired columns: PropTypes.array.isRequired,
dataChangeListener: PropTypes.object
} }
constructor(props) { constructor(props) {
super(props); super(props);
this.currFilters = {}; this.currFilters = {};
this.onFilter = this.onFilter.bind(this); this.onFilter = this.onFilter.bind(this);
this.doFilter = this.doFilter.bind(this);
this.onExternalFilter = this.onExternalFilter.bind(this); this.onExternalFilter = this.onExternalFilter.bind(this);
this.state = {
data: props.data
};
} }
componentDidMount() { componentDidMount() {
@@ -33,6 +38,16 @@ export default (
} }
} }
componentWillReceiveProps(nextProps) {
let nextData = nextProps.data;
if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.props.data)) {
nextData = this.doFilter(nextProps);
}
this.setState({
data: nextData
});
}
onFilter(column, filterType, initialize = false) { onFilter(column, filterType, initialize = false) {
return (filterVal) => { return (filterVal) => {
// watch out here if migration to context API, #334 // watch out here if migration to context API, #334
@@ -64,11 +79,13 @@ export default (
return; return;
} }
let result;
if (filter.props.onFilter) { if (filter.props.onFilter) {
filter.props.onFilter(filterVal); result = filter.props.onFilter(filterVal);
} }
this.forceUpdate(); result = this.doFilter(this.props, result);
this.setState({ data: result });
}; };
} }
@@ -78,14 +95,21 @@ export default (
}; };
} }
render() { doFilter(props, customResult) {
let { data } = this.props; let result = customResult;
if (!isRemoteFiltering()) {
data = filters(data, this.props.columns, _)(this.currFilters); const { dataChangeListener, data, columns } = props;
result = result || filters(data, columns, _)(this.currFilters);
if (dataChangeListener) {
dataChangeListener.emit('filterChanged', result.length);
} }
return result;
}
render() {
return ( return (
<FilterContext.Provider value={ { <FilterContext.Provider value={ {
data, data: this.state.data,
onFilter: this.onFilter, onFilter: this.onFilter,
onExternalFilter: this.onExternalFilter onExternalFilter: this.onExternalFilter
} } } }

View File

@@ -45,7 +45,8 @@ describe('FilterContext', () => {
function shallowContext( function shallowContext(
enableRemote = false, enableRemote = false,
tableColumns = columns tableColumns = columns,
dataChangeListener,
) { ) {
mockBase.mockReset(); mockBase.mockReset();
handleFilterChange.mockReset(); handleFilterChange.mockReset();
@@ -59,6 +60,7 @@ describe('FilterContext', () => {
<FilterContext.Provider <FilterContext.Provider
columns={ tableColumns } columns={ tableColumns }
data={ data } data={ data }
dataChangeListener={ dataChangeListener }
> >
<FilterContext.Consumer> <FilterContext.Consumer>
{ {
@@ -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', () => { describe('combination', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(shallowContext()); wrapper = shallow(shallowContext());

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-paginator", "name": "react-bootstrap-table2-paginator",
"version": "2.0.1", "version": "2.0.2",
"description": "it's the pagination addon for react-bootstrap-table2", "description": "it's the pagination addon for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -2,7 +2,9 @@
/* eslint react/require-default-props: 0 */ /* eslint react/require-default-props: 0 */
/* eslint no-lonely-if: 0 */ /* eslint no-lonely-if: 0 */
import React from 'react'; import React from 'react';
import EventEmitter from 'events';
import Const from './const'; import Const from './const';
import { alignPage } from './page';
const StateContext = React.createContext(); const StateContext = React.createContext();
@@ -10,6 +12,7 @@ class StateProvider extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleChangePage = this.handleChangePage.bind(this); this.handleChangePage = this.handleChangePage.bind(this);
this.handleDataSizeChange = this.handleDataSizeChange.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this); this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
let currPage; let currPage;
@@ -36,7 +39,10 @@ class StateProvider extends React.Component {
} }
this.currPage = currPage; this.currPage = currPage;
this.dataSize = options.totalSize;
this.currSizePerPage = currSizePerPage; this.currSizePerPage = currSizePerPage;
this.dataChangeListener = new EventEmitter();
this.dataChangeListener.on('filterChanged', this.handleDataSizeChange);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
@@ -46,12 +52,13 @@ class StateProvider extends React.Component {
if (this.isRemotePagination() || custom) { if (this.isRemotePagination() || custom) {
this.currPage = nextProps.pagination.options.page; this.currPage = nextProps.pagination.options.page;
this.currSizePerPage = nextProps.pagination.options.sizePerPage; this.currSizePerPage = nextProps.pagination.options.sizePerPage;
this.dataSize = nextProps.pagination.options.totalSize;
} }
} }
getPaginationProps = () => { getPaginationProps = () => {
const { pagination: { options }, bootstrap4 } = this.props; const { pagination: { options }, bootstrap4 } = this.props;
const { currPage, currSizePerPage } = this; const { currPage, currSizePerPage, dataSize } = this;
const withFirstAndLast = typeof options.withFirstAndLast === 'undefined' ? const withFirstAndLast = typeof options.withFirstAndLast === 'undefined' ?
Const.With_FIRST_AND_LAST : options.withFirstAndLast; Const.With_FIRST_AND_LAST : options.withFirstAndLast;
const alwaysShowAllBtns = typeof options.alwaysShowAllBtns === 'undefined' ? const alwaysShowAllBtns = typeof options.alwaysShowAllBtns === 'undefined' ?
@@ -72,7 +79,7 @@ class StateProvider extends React.Component {
hideSizePerPage, hideSizePerPage,
alwaysShowAllBtns, alwaysShowAllBtns,
withFirstAndLast, withFirstAndLast,
dataSize: options.totalSize, dataSize,
sizePerPageList: options.sizePerPageList || Const.SIZE_PER_PAGE_LIST, sizePerPageList: options.sizePerPageList || Const.SIZE_PER_PAGE_LIST,
paginationSize: options.paginationSize || Const.PAGINATION_SIZE, paginationSize: options.paginationSize || Const.PAGINATION_SIZE,
showTotal: options.showTotal, showTotal: options.showTotal,
@@ -106,6 +113,20 @@ class StateProvider extends React.Component {
return e.result; 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) { handleChangePage(currPage) {
const { currSizePerPage } = this; const { currSizePerPage } = this;
const { pagination: { options } } = this.props; const { pagination: { options } } = this.props;
@@ -153,7 +174,8 @@ class StateProvider extends React.Component {
paginationProps, paginationProps,
paginationTableProps: { paginationTableProps: {
pagination, pagination,
setPaginationRemoteEmitter: this.setPaginationRemoteEmitter setPaginationRemoteEmitter: this.setPaginationRemoteEmitter,
dataChangeListener: this.dataChangeListener
} }
} } } }
> >

View File

@@ -91,6 +91,10 @@ describe('PaginationStateContext', () => {
expect(wrapper.instance().currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]); 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', () => { it('should get correct pagination props', () => {
const instance = wrapper.instance(); const instance = wrapper.instance();
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
@@ -102,7 +106,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -149,7 +154,7 @@ describe('PaginationStateContext', () => {
setRemotePaginationEmitter(instance, true); setRemotePaginationEmitter(instance, true);
nextProps = { nextProps = {
data, data,
pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5 } } pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5, totalSize: 50 } }
}; };
instance.componentWillReceiveProps(nextProps); instance.componentWillReceiveProps(nextProps);
}); });
@@ -157,6 +162,7 @@ describe('PaginationStateContext', () => {
it('should always reset currPage and currSizePerPage', () => { it('should always reset currPage and currSizePerPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page); expect(instance.currPage).toEqual(nextProps.pagination.options.page);
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage); 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); setRemotePaginationEmitter(instance, true);
nextProps = { nextProps = {
data, data,
pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5, custom: true } } pagination: {
...defaultPagination,
options: { page: 3, sizePerPage: 5, custom: true, totalSize: 50 }
}
}; };
instance.componentWillReceiveProps(nextProps); instance.componentWillReceiveProps(nextProps);
}); });
@@ -178,10 +187,36 @@ describe('PaginationStateContext', () => {
it('should always reset currPage and currSizePerPage', () => { it('should always reset currPage and currSizePerPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page); expect(instance.currPage).toEqual(nextProps.pagination.options.page);
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage); 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', () => { describe('handleChangePage', () => {
let instance; let instance;
const newPage = 3; const newPage = 3;
@@ -343,7 +378,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -374,7 +410,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -401,7 +438,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -428,7 +466,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -455,7 +494,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -482,7 +522,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -509,7 +550,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -536,7 +578,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -563,7 +606,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -590,7 +634,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -617,7 +662,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -644,7 +690,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -671,7 +718,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -698,7 +746,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -725,7 +774,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -752,7 +802,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -779,7 +830,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -806,7 +858,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });
@@ -833,7 +886,8 @@ describe('PaginationStateContext', () => {
createContext: expect.any(Function), createContext: expect.any(Function),
options: instance.getPaginationProps() options: instance.getPaginationProps()
}, },
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter,
dataChangeListener: expect.any(Object)
} }
}); });
}); });

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-toolkit", "name": "react-bootstrap-table2-toolkit",
"version": "1.2.0", "version": "1.2.2",
"description": "The toolkit for react-bootstrap-table2", "description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -1,6 +1,8 @@
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
/* eslint react/require-default-props: 0 */ /* eslint react/require-default-props: 0 */
/* eslint no-continue: 0 */ /* eslint no-continue: 0 */
/* eslint no-lonely-if: 0 */
/* eslint class-methods-use-this: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@@ -17,36 +19,55 @@ export default (options = {
static propTypes = { static propTypes = {
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
columns: PropTypes.array.isRequired, columns: PropTypes.array.isRequired,
searchText: PropTypes.string searchText: PropTypes.string,
dataChangeListener: PropTypes.object
} }
constructor(props) { constructor(props) {
super(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);
this.triggerListener(initialData);
}
this.state = { data: initialData };
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (isRemoteSearch()) { if (nextProps.searchText !== this.props.searchText) {
if (nextProps.searchText !== this.props.searchText) { if (isRemoteSearch()) {
this.performRemoteSearch = true; handleRemoteSearchChange(nextProps.searchText);
} else { } else {
this.performRemoteSearch = false; const result = this.search(nextProps);
this.triggerListener(result);
this.setState({
data: result
});
}
} else {
if (isRemoteSearch()) {
this.setState({ data: nextProps.data });
} else if (!_.isEqual(nextProps.data, this.props.data)) {
const result = this.search(nextProps);
this.triggerListener(result);
this.setState({
data: result
});
} }
} }
} }
search() { triggerListener(result) {
const { data, columns } = this.props; if (this.props.dataChangeListener) {
let { searchText } = this.props; this.props.dataChangeListener.emit('filterChanged', result.length);
if (isRemoteSearch()) {
if (this.performRemoteSearch) {
handleRemoteSearchChange(searchText);
}
return data;
} }
}
searchText = searchText.toLowerCase(); search(props) {
const { data, columns } = props;
const searchText = props.searchText.toLowerCase();
return data.filter((row, ridx) => { return data.filter((row, ridx) => {
for (let cidx = 0; cidx < columns.length; cidx += 1) { for (let cidx = 0; cidx < columns.length; cidx += 1) {
const column = columns[cidx]; const column = columns[cidx];
@@ -69,9 +90,8 @@ export default (options = {
} }
render() { render() {
const data = this.search();
return ( return (
<SearchContext.Provider value={ { data } }> <SearchContext.Provider value={ { data: this.state.data } }>
{ this.props.children } { this.props.children }
</SearchContext.Provider> </SearchContext.Provider>
); );

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table-next", "name": "react-bootstrap-table-next",
"version": "2.1.0", "version": "2.1.2",
"description": "Next generation of react-bootstrap-table", "description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -15,9 +15,36 @@ import withRowExpansion from './row-expand/row-consumer';
class Body extends React.Component { class Body extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
if (props.cellEdit.createContext) { const {
this.EditingCell = props.cellEdit.createEditingCell(_, props.cellEdit.options.onStartEdit); 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() { render() {
@@ -46,21 +73,12 @@ class Body extends React.Component {
} }
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />; content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
} else { } else {
let RowComponent = SimpleRow;
const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED; const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
const expandRowEnabled = !!expandRow.renderer; const expandRowEnabled = !!expandRow.renderer;
const additionalRowProps = {}; const additionalRowProps = {};
if (expandRowEnabled) {
RowComponent = withRowExpansion(RowAggregator, visibleColumnSize);
}
if (selectRowEnabled) {
RowComponent = withRowSelection(expandRowEnabled ? RowComponent : RowAggregator);
}
if (cellEdit.createContext) { if (cellEdit.createContext) {
RowComponent = cellEdit.withRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _);
additionalRowProps.EditingCellComponent = this.EditingCell; additionalRowProps.EditingCellComponent = this.EditingCell;
} }
@@ -88,7 +106,7 @@ class Body extends React.Component {
baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle; baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses); baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
return <RowComponent { ...baseRowProps } />; return <this.RowComponent { ...baseRowProps } />;
}); });
} }

View File

@@ -106,6 +106,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
<Footer <Footer
data={ this.getData() } data={ this.getData() }
columns={ columns } columns={ columns }
selectRow={ selectRow }
expandRow={ expandRow }
className={ this.props.footerClasses } className={ this.props.footerClasses }
/> />
)} )}

View File

@@ -217,6 +217,7 @@ const withContext = Base =>
ref={ n => this.searchContext = n } ref={ n => this.searchContext = n }
data={ rootProps.getData(filterProps) } data={ rootProps.getData(filterProps) }
searchText={ this.props.search.searchText } searchText={ this.props.search.searchText }
dataChangeListener={ this.props.dataChangeListener }
> >
<this.SearchContext.Consumer> <this.SearchContext.Consumer>
{ {
@@ -237,6 +238,7 @@ const withContext = Base =>
{ ...baseProps } { ...baseProps }
ref={ n => this.filterContext = n } ref={ n => this.filterContext = n }
data={ rootProps.getData() } data={ rootProps.getData() }
dataChangeListener={ this.props.dataChangeListener }
> >
<this.FilterContext.Consumer> <this.FilterContext.Consumer>
{ {

View File

@@ -2,31 +2,52 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Const from './const';
import FooterCell from './footer-cell'; import FooterCell from './footer-cell';
import _ from './utils'; import _ from './utils';
const Footer = (props) => { const Footer = (props) => {
const { data, className, columns } = props; const { data, className, columns, selectRow, expandRow } = props;
const SelectionFooterCellComp = () => <th />;
const ExpansionFooterCellComp = () => <th />;
const isRenderExpandColumnInLeft = (
expandColumnPosition = Const.INDICATOR_POSITION_LEFT
) => expandColumnPosition === Const.INDICATOR_POSITION_LEFT;
const childrens = columns.map((column, i) => {
if (column.footer === undefined || column.footer === null || column.hidden) {
return false;
}
const columnData = _.pluck(data, column.dataField);
return (
<FooterCell
index={ i }
key={ column.dataField }
column={ column }
columnData={ columnData }
/>
);
});
if (selectRow && selectRow.hideSelectColumn !== true) {
childrens.unshift(<SelectionFooterCellComp key="selection" />);
}
if (expandRow.showExpandColumn) {
if (isRenderExpandColumnInLeft(expandRow.expandColumnPosition)) {
childrens.unshift(<ExpansionFooterCellComp key="expansion" />);
} else {
childrens.push(<ExpansionFooterCellComp key="expansion" />);
}
}
return ( return (
<tfoot> <tfoot>
<tr className={ className }> <tr className={ className }>
{columns.map((column, i) => { { childrens }
if (column.footer === undefined || column.footer === null || column.hidden) {
return false;
}
const columnData = _.pluck(data, column.dataField);
return (
<FooterCell
index={ i }
key={ column.dataField }
column={ column }
columnData={ columnData }
/>
);
})}
</tr> </tr>
</tfoot> </tfoot>
); );
@@ -35,7 +56,9 @@ const Footer = (props) => {
Footer.propTypes = { Footer.propTypes = {
data: PropTypes.array, data: PropTypes.array,
className: PropTypes.string, className: PropTypes.string,
columns: PropTypes.array columns: PropTypes.array,
selectRow: PropTypes.object,
expandRow: PropTypes.object
}; };
export default Footer; export default Footer;

View File

@@ -1,8 +1,9 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import 'jsdom-global/register'; import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import { shallow, mount } from 'enzyme'; import { shallow, render } from 'enzyme';
import Const from '../src/const';
import Footer from '../src/footer'; import Footer from '../src/footer';
import FooterCell from '../src/footer-cell'; import FooterCell from '../src/footer-cell';
@@ -32,11 +33,29 @@ describe('Footer', () => {
} }
]; ];
const selectRow = {
mode: Const.ROW_SELECT_DISABLED,
selected: [],
hideSelectColumn: true
};
const expandRow = {
renderer: undefined,
expanded: [],
nonExpandable: []
};
const keyField = 'id'; const keyField = 'id';
describe('simplest footer', () => { describe('simplest footer', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(<Footer data={ data } columns={ columns } />); wrapper = shallow(
<Footer
data={ data }
columns={ columns }
selectRow={ selectRow }
expandRow={ expandRow }
/>
);
}); });
it('should render successfully', () => { it('should render successfully', () => {
@@ -50,7 +69,15 @@ describe('Footer', () => {
const className = 'test-class'; const className = 'test-class';
beforeEach(() => { beforeEach(() => {
wrapper = shallow(<Footer data={ data } columns={ columns } className={ className } />); wrapper = shallow(
<Footer
data={ data }
columns={ columns }
className={ className }
selectRow={ selectRow }
expandRow={ expandRow }
/>
);
}); });
it('should render successfully', () => { it('should render successfully', () => {
@@ -58,4 +85,40 @@ describe('Footer', () => {
expect(wrapper.find(`.${className}`).length).toBe(1); expect(wrapper.find(`.${className}`).length).toBe(1);
}); });
}); });
describe('when selecrRow prop is enable', () => {
beforeEach(() => {
wrapper = render(
<Footer
data={ data }
columns={ columns }
selectRow={ { ...selectRow, mode: 'radio', hideSelectColumn: false } }
expandRow={ expandRow }
/>
);
});
it('should render successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find('th').length).toBe(columns.length + 1);
});
});
describe('when expandRow prop is enable', () => {
beforeEach(() => {
wrapper = render(
<Footer
data={ data }
columns={ columns }
selectRow={ selectRow }
expandRow={ { expandRow, showExpandColumn: true } }
/>
);
});
it('should render successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find('th').length).toBe(columns.length + 1);
});
});
}); });