mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2026-06-29 05:30:05 +00:00
Compare commits
59 Commits
react-boot
...
react-boot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37e79a654b | ||
|
|
4e7cfdf5ea | ||
|
|
6f4e779a3e | ||
|
|
38d3e2df05 | ||
|
|
4e204f1ccd | ||
|
|
7e29999b40 | ||
|
|
01cf69392f | ||
|
|
7d7688582b | ||
|
|
e26065b116 | ||
|
|
485503c54d | ||
|
|
3c37716dd2 | ||
|
|
1a7f86a321 | ||
|
|
475f8c67b0 | ||
|
|
26314254be | ||
|
|
6522f6d964 | ||
|
|
ecaf439e66 | ||
|
|
90d03676ad | ||
|
|
2585a62697 | ||
|
|
6afe58a081 | ||
|
|
6f5bd1a13d | ||
|
|
85a9ab72af | ||
|
|
258ea43225 | ||
|
|
7a7b708029 | ||
|
|
0cf89861af | ||
|
|
eb74625835 | ||
|
|
cbaec4c655 | ||
|
|
04c21cb63d | ||
|
|
7d72002b6e | ||
|
|
279cc25da0 | ||
|
|
1152bb8440 | ||
|
|
88befb8136 | ||
|
|
42c6bc0337 | ||
|
|
6e753bb955 | ||
|
|
64df3e1fae | ||
|
|
5cdd1ad093 | ||
|
|
36e754b6bc | ||
|
|
6730dcf60d | ||
|
|
fb54809dc9 | ||
|
|
d43c622fdb | ||
|
|
7253d7a1d7 | ||
|
|
a6daa50417 | ||
|
|
b11019ce20 | ||
|
|
dda47f7b7d | ||
|
|
4da8ba7ecc | ||
|
|
2ff0b27747 | ||
|
|
c3f279fb0c | ||
|
|
06bcf1edca | ||
|
|
fc1f75cfac | ||
|
|
1cf12ab707 | ||
|
|
288ccc1049 | ||
|
|
f13c139f63 | ||
|
|
e72ad0586e | ||
|
|
c2044fe8b5 | ||
|
|
a7b3690a7c | ||
|
|
68afc348db | ||
|
|
5404124a78 | ||
|
|
d592871c0d | ||
|
|
6019e550fd | ||
|
|
19ba336e32 |
@@ -18,6 +18,7 @@
|
|||||||
* [id](#id)
|
* [id](#id)
|
||||||
* [classes](#classes)
|
* [classes](#classes)
|
||||||
* [wrapperClasses](#wrapperClasses)
|
* [wrapperClasses](#wrapperClasses)
|
||||||
|
* [headerClasses](#headerClasses)
|
||||||
* [cellEdit](#cellEdit)
|
* [cellEdit](#cellEdit)
|
||||||
* [selectRow](#selectRow)
|
* [selectRow](#selectRow)
|
||||||
* [rowStyle](#rowStyle)
|
* [rowStyle](#rowStyle)
|
||||||
@@ -111,6 +112,10 @@ Customize class on `table` element.
|
|||||||
|
|
||||||
### <a name='wrapperClasses'>wrapperClasses - [String]</a>
|
### <a name='wrapperClasses'>wrapperClasses - [String]</a>
|
||||||
Customize class on the outer element which wrap up the `table` element.
|
Customize class on the outer element which wrap up the `table` element.
|
||||||
|
|
||||||
|
### <a name='headerClasses'>headerClasses - [String]</a>
|
||||||
|
Customize class on the header row(`tr`).
|
||||||
|
|
||||||
### <a name='cellEdit'>cellEdit - [Object]</a>
|
### <a name='cellEdit'>cellEdit - [Object]</a>
|
||||||
Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail.
|
Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail.
|
||||||
|
|
||||||
@@ -202,6 +207,7 @@ paginator({
|
|||||||
totalSize, // Total data size. It's necessary when remote is enabled
|
totalSize, // Total data size. It's necessary when remote is enabled
|
||||||
pageStartIndex: 0, // first page will be 0, default is 1
|
pageStartIndex: 0, // first page will be 0, default is 1
|
||||||
paginationSize: 3, // the pagination bar size, default is 5
|
paginationSize: 3, // the pagination bar size, default is 5
|
||||||
|
showTotal: true, // display pagination information
|
||||||
sizePerPageList: [ {
|
sizePerPageList: [ {
|
||||||
text: '5', value: 5
|
text: '5', value: 5
|
||||||
}, {
|
}, {
|
||||||
@@ -223,6 +229,7 @@ paginator({
|
|||||||
hidePageListOnlyOnePage: true, // hide pagination bar when only one page, default is false
|
hidePageListOnlyOnePage: true, // hide pagination bar when only one page, default is false
|
||||||
onPageChange: (page, sizePerPage) => {}, // callback function when page was changing
|
onPageChange: (page, sizePerPage) => {}, // callback function when page was changing
|
||||||
onSizePerPageChange: (sizePerPage, page) => {}, // callback function when page size was changing
|
onSizePerPageChange: (sizePerPage, page) => {}, // callback function when page size was changing
|
||||||
|
paginationTotalRenderer: (from, to, size) => { ... } // custom the pagination total
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -648,6 +648,8 @@ Configure `column.filter` will able to setup a column level filter on the header
|
|||||||
|
|
||||||
* Text(`textFilter`)
|
* Text(`textFilter`)
|
||||||
* Select(`selectFilter`)
|
* Select(`selectFilter`)
|
||||||
|
* Number(`numberFilter`)
|
||||||
|
* Date(`dateFilter`)
|
||||||
|
|
||||||
We have a quick example to show you how to use `column.filter`:
|
We have a quick example to show you how to use `column.filter`:
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](ht
|
|||||||
Please see [Work with selection](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-row-select.html).
|
Please see [Work with selection](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-row-select.html).
|
||||||
Please see [available selectRow configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/row-select-props.html).
|
Please see [available selectRow configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/row-select-props.html).
|
||||||
|
|
||||||
No huge change for row selection, but can not custom the selection column currently. Coming soon!!!
|
No huge change for row selection.
|
||||||
|
|
||||||
## Column Filter
|
## Column Filter
|
||||||
|
|
||||||
@@ -82,14 +82,14 @@ Please see [available filter configuration](https://react-bootstrap-table.github
|
|||||||
- [x] Text Filter
|
- [x] Text Filter
|
||||||
- [x] Custom Text Filter
|
- [x] Custom Text Filter
|
||||||
- [x] Remote Filter
|
- [x] Remote Filter
|
||||||
- [ ] Custom Filter Component
|
- [x] Custom Filter Component
|
||||||
- [ ] Regex Filter
|
- [ ] Regex Filter
|
||||||
- [x] Select Filter
|
- [x] Select Filter
|
||||||
- [x] Custom Select Filter
|
- [x] Custom Select Filter
|
||||||
- [X] Number Filter
|
- [X] Number Filter
|
||||||
- [ ] Date Filter
|
- [X] Date Filter
|
||||||
- [ ] Array Filter
|
- [X] Array Filter
|
||||||
- [ ] Programmatically Filter
|
- [X] Programmatically Filter
|
||||||
|
|
||||||
Remember to install [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter) firstly.
|
Remember to install [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter) firstly.
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
* [onSelect](#onSelect)
|
* [onSelect](#onSelect)
|
||||||
* [onSelectAll](#onSelectAll)
|
* [onSelectAll](#onSelectAll)
|
||||||
* [hideSelectColumn](#hideSelectColumn)
|
* [hideSelectColumn](#hideSelectColumn)
|
||||||
|
* [selectionRenderer](#selectionRenderer)
|
||||||
|
* [selectionHeaderRenderer](#selectionHeaderRenderer)
|
||||||
|
|
||||||
### <a name="mode">selectRow.mode - [String]</a>
|
### <a name="mode">selectRow.mode - [String]</a>
|
||||||
|
|
||||||
@@ -156,6 +158,34 @@ const selectRow = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <a name='selectionRenderer'>selectRow.selectionRenderer - [Function]</a>
|
||||||
|
Provide a callback function which allow you to custom the checkbox/radio box. This callback only have one argument which is an object and contain following properties:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
selectionRenderer: ({ mode, checked, disabled }) => (
|
||||||
|
// ....
|
||||||
|
)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> By default, `react-bootstrap-table2` will help you to handle the click event, it's not necessary to handle again by developer.
|
||||||
|
|
||||||
|
### <a name='selectionHeaderRenderer'>selectRow.selectionHeaderRenderer - [Function]</a>
|
||||||
|
Provide a callback function which allow you to custom the checkbox/radio box in the selection header column. This callback only have one argument which is an object and contain following properties:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
selectionHeaderRenderer: ({ mode, checked, indeterminate }) => (
|
||||||
|
// ....
|
||||||
|
)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> By default, `react-bootstrap-table2` will help you to handle the click event, it's not necessary to handle again by developer.
|
||||||
|
|
||||||
### <a name='onSelect'>selectRow.onSelect - [Function]</a>
|
### <a name='onSelect'>selectRow.onSelect - [Function]</a>
|
||||||
This callback function will be called when a row is select/unselect and pass following three arguments:
|
This callback function will be called when a row is select/unselect and pass following three arguments:
|
||||||
`row`, `isSelect`, `rowIndex` and `e`.
|
`row`, `isSelect`, `rowIndex` and `e`.
|
||||||
|
|||||||
184
packages/react-bootstrap-table2-example/examples/column-filter/advance-custom-filter.js
vendored
Normal file
184
packages/react-bootstrap-table2-example/examples/column-filter/advance-custom-filter.js
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter, customFilter, Comparator, FILTER_TYPES } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
class PriceFilter extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
onFilter: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
this.getValue = this.getValue.bind(this);
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
this.state = { value: 2100 };
|
||||||
|
}
|
||||||
|
onChange(e) {
|
||||||
|
this.setState({ value: e.target.value });
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
filter() {
|
||||||
|
this.props.onFilter({
|
||||||
|
number: this.getValue(),
|
||||||
|
comparator: this.select.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="2100"
|
||||||
|
max="2110"
|
||||||
|
onChange={ this.onChange }
|
||||||
|
/>,
|
||||||
|
<p
|
||||||
|
key="show"
|
||||||
|
ref={ node => this.showValue = node }
|
||||||
|
style={ { textAlign: 'center' } }
|
||||||
|
>
|
||||||
|
{ this.state.value }
|
||||||
|
</p>,
|
||||||
|
<select
|
||||||
|
key="select"
|
||||||
|
ref={ node => this.select = node }
|
||||||
|
className="form-control"
|
||||||
|
>
|
||||||
|
<option value={ Comparator.GT }>></option>
|
||||||
|
<option value={ Comparator.EQ }>=</option>
|
||||||
|
<option value={ Comparator.LT }><</option>
|
||||||
|
</select>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-warning"
|
||||||
|
onClick={ this.filter }
|
||||||
|
>
|
||||||
|
{ `Filter ${this.props.column.text}` }
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter()
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: customFilter({
|
||||||
|
type: FILTER_TYPES.NUMBER // ask react-bootstrap-table to filter data as number
|
||||||
|
}),
|
||||||
|
filterRenderer: (onFilter, column) =>
|
||||||
|
<PriceFilter onFilter={ onFilter } column={ column } />
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter, customFilter, Comparator, FILTER_TYPES } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
class PriceFilter extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
onFilter: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
this.getValue = this.getValue.bind(this);
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
this.state = { value: 2100 };
|
||||||
|
}
|
||||||
|
onChange(e) {
|
||||||
|
this.setState({ value: e.target.value });
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
filter() {
|
||||||
|
this.props.onFilter({
|
||||||
|
number: this.getValue(),
|
||||||
|
comparator: this.select.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="2100"
|
||||||
|
max="2110"
|
||||||
|
onChange={ this.onChange }
|
||||||
|
/>,
|
||||||
|
<p
|
||||||
|
key="show"
|
||||||
|
ref={ node => this.showValue = node }
|
||||||
|
style={ { textAlign: 'center' } }
|
||||||
|
>
|
||||||
|
{ this.state.value }
|
||||||
|
</p>,
|
||||||
|
<select
|
||||||
|
key="select"
|
||||||
|
ref={ node => this.select = node }
|
||||||
|
className="form-control"
|
||||||
|
>
|
||||||
|
<option value={ Comparator.GT }>></option>
|
||||||
|
<option value={ Comparator.EQ }>=</option>
|
||||||
|
<option value={ Comparator.LT }><</option>
|
||||||
|
</select>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-warning"
|
||||||
|
onClick={ this.filter }
|
||||||
|
>
|
||||||
|
{ \`Filter $\{this.props.column.text}\` }
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter()
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: customFilter({
|
||||||
|
type: FILTER_TYPES.NUMBER // ask react-bootstrap-table to filter data as number
|
||||||
|
}),
|
||||||
|
filterRenderer: (onFilter, column) =>
|
||||||
|
<PriceFilter onFilter={ onFilter } column={ column } />
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
77
packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js
vendored
Normal file
77
packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { stockGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const stocks = stockGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter({
|
||||||
|
delay: 400,
|
||||||
|
placeholder: 'custom placeholder',
|
||||||
|
withoutEmptyComparatorOption: true,
|
||||||
|
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
|
||||||
|
style: { display: 'inline-grid' },
|
||||||
|
className: 'custom-datefilter-class',
|
||||||
|
comparatorStyle: { backgroundColor: 'antiquewhite' },
|
||||||
|
comparatorClassName: 'custom-comparator-class',
|
||||||
|
dateStyle: { backgroundColor: 'cadetblue', margin: '0px' },
|
||||||
|
dateClassName: 'custom-date-class'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter({
|
||||||
|
delay: 400,
|
||||||
|
placeholder: 'custom placeholder',
|
||||||
|
withoutEmptyComparatorOption: true,
|
||||||
|
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
|
||||||
|
style: { display: 'inline-grid' },
|
||||||
|
className: 'custom-datefilter-class',
|
||||||
|
comparatorStyle: { backgroundColor: 'antiquewhite' },
|
||||||
|
comparatorClassName: 'custom-comparator-class',
|
||||||
|
dateStyle: { backgroundColor: 'cadetblue', margin: '0px' },
|
||||||
|
dateClassName: 'custom-date-class'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
128
packages/react-bootstrap-table2-example/examples/column-filter/custom-filter.js
vendored
Normal file
128
packages/react-bootstrap-table2-example/examples/column-filter/custom-filter.js
vendored
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter, customFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
class PriceFilter extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
onFilter: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
this.getValue = this.getValue.bind(this);
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return this.input.value;
|
||||||
|
}
|
||||||
|
filter() {
|
||||||
|
this.props.onFilter(this.getValue());
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
key="input"
|
||||||
|
ref={ node => this.input = node }
|
||||||
|
type="text"
|
||||||
|
placeholder="Input price"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-warning"
|
||||||
|
onClick={ this.filter }
|
||||||
|
>
|
||||||
|
{ `Find ${this.props.column.text}` }
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter()
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: customFilter(),
|
||||||
|
filterRenderer: (onFilter, column) =>
|
||||||
|
<PriceFilter onFilter={ onFilter } column={ column } />
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter, customFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
class PriceFilter extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
onFilter: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
this.getValue = this.getValue.bind(this);
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return this.input.value;
|
||||||
|
}
|
||||||
|
filter() {
|
||||||
|
this.props.onFilter(this.getValue());
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
key="input"
|
||||||
|
ref={ node => this.input = node }
|
||||||
|
type="text"
|
||||||
|
placeholder="Input price"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-warning"
|
||||||
|
onClick={ this.filter }
|
||||||
|
>
|
||||||
|
{ \`Filter $\{this.props.column.text}\` }
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter()
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: customFilter(),
|
||||||
|
filterRenderer: (onFilter, column) =>
|
||||||
|
<PriceFilter onFilter={ onFilter } column={ column } />
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
80
packages/react-bootstrap-table2-example/examples/column-filter/custom-multi-select-filter.js
vendored
Normal file
80
packages/react-bootstrap-table2-example/examples/column-filter/custom-multi-select-filter.js
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
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: multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
withoutEmptyOption: true,
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'pink'
|
||||||
|
},
|
||||||
|
className: 'test-classname',
|
||||||
|
datamycustomattr: 'datamycustomattr'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
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: multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
withoutEmptyOption: true,
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'pink'
|
||||||
|
},
|
||||||
|
className: 'test-classname',
|
||||||
|
datamycustomattr: 'datamycustomattr'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
59
packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js
vendored
Normal file
59
packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { stockGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const stocks = stockGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter({
|
||||||
|
defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT }
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter({
|
||||||
|
defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT }
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
55
packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js
vendored
Normal file
55
packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { stockGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const stocks = stockGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
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: multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
defaultValue: [0, 2]
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
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: multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
defaultValue: [0, 2]
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
67
packages/react-bootstrap-table2-example/examples/column-filter/multi-select-filter.js
vendored
Normal file
67
packages/react-bootstrap-table2-example/examples/column-filter/multi-select-filter.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
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: multiSelectFilter({
|
||||||
|
options: selectOptions
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
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: multiSelectFilter({
|
||||||
|
options: selectOptions
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
85
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js
vendored
Normal file
85
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { stockGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const stocks = stockGenerator(8);
|
||||||
|
|
||||||
|
let inStockDateFilter;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter({
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// inStockDateFilter was assigned once the component has been mounted.
|
||||||
|
inStockDateFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
inStockDateFilter({
|
||||||
|
date: new Date(2018, 0, 1),
|
||||||
|
comparator: Comparator.GT
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
let inStockDateFilter;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'InStock Date',
|
||||||
|
filter: dateFilter({
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// inStockDateFilter was assigned once the component has been mounted.
|
||||||
|
inStockDateFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
inStockDateFilter({
|
||||||
|
date: new Date(2018, 0, 1),
|
||||||
|
comparator: Comparator.GT
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter InStock Date columns which is greater than 2018.01.01 </button>
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ stocks } columns={ columns } filter={ filterFactory() } />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter InStock Date columns which is greater than 2018.01.01 </button>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
let qualityFilter;
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
0: 'good',
|
||||||
|
1: 'Bad',
|
||||||
|
2: 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
formatter: cell => selectOptions[cell],
|
||||||
|
filter: multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// qualityFilter was assigned once the component has been mounted.
|
||||||
|
qualityFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
qualityFilter([0, 2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
let qualityFilter;
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
0: 'good',
|
||||||
|
1: 'Bad',
|
||||||
|
2: 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
formatter: cell => selectOptions[cell],
|
||||||
|
filter: multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// qualityFilter was assigned once the component has been mounted.
|
||||||
|
qualityFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
qualityFilter([0, 2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }>{' filter columns by option "good" and "unknow" '}</button>
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }>{' filter columns by option "good" and "unknow" '}</button>
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
52
packages/react-bootstrap-table2-example/examples/header-columns/header-class-table.js
vendored
Normal file
52
packages/react-bootstrap-table2-example/examples/header-columns/header-class-table.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
headerClasses="header-class"
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
headerClasses="header-class"
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -24,6 +24,12 @@ import BootstrapTable from 'react-bootstrap-table-next';
|
|||||||
import paginationFactory from 'react-bootstrap-table2-paginator';
|
import paginationFactory from 'react-bootstrap-table2-paginator';
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
|
const customTotal = (from, to, size) => (
|
||||||
|
<span className="react-bootstrap-table-pagination-total">
|
||||||
|
Showing { from } to { to } of { size } Results
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
paginationSize: 4,
|
paginationSize: 4,
|
||||||
pageStartIndex: 0,
|
pageStartIndex: 0,
|
||||||
@@ -39,6 +45,8 @@ const options = {
|
|||||||
prePageTitle: 'Pre page',
|
prePageTitle: 'Pre page',
|
||||||
firstPageTitle: 'Next page',
|
firstPageTitle: 'Next page',
|
||||||
lastPageTitle: 'Last page',
|
lastPageTitle: 'Last page',
|
||||||
|
showTotal: true,
|
||||||
|
paginationTotalRenderer: customTotal,
|
||||||
sizePerPageList: [{
|
sizePerPageList: [{
|
||||||
text: '5', value: 5
|
text: '5', value: 5
|
||||||
}, {
|
}, {
|
||||||
@@ -50,11 +58,18 @@ const options = {
|
|||||||
|
|
||||||
<BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginationFactory(options) } />
|
<BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginationFactory(options) } />
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const customTotal = (from, to, size) => (
|
||||||
|
<span className="react-bootstrap-table-pagination-total">
|
||||||
|
Showing { from } to { to } of { size } Results
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
paginationSize: 4,
|
paginationSize: 4,
|
||||||
pageStartIndex: 0,
|
pageStartIndex: 0,
|
||||||
// alwaysShowAllBtns: true // Always show next and previous button
|
// alwaysShowAllBtns: true, // Always show next and previous button
|
||||||
// withFirstAndLast: false // Hide the going to First and Last page button
|
// withFirstAndLast: false, // Hide the going to First and Last page button
|
||||||
// hideSizePerPage: true, // Hide the sizePerPage dropdown always
|
// hideSizePerPage: true, // Hide the sizePerPage dropdown always
|
||||||
// hidePageListOnlyOnePage: true, // Hide the pagination list when only one page
|
// hidePageListOnlyOnePage: true, // Hide the pagination list when only one page
|
||||||
firstPageText: 'First',
|
firstPageText: 'First',
|
||||||
@@ -66,6 +81,7 @@ const options = {
|
|||||||
firstPageTitle: 'Next page',
|
firstPageTitle: 'Next page',
|
||||||
lastPageTitle: 'Last page',
|
lastPageTitle: 'Last page',
|
||||||
showTotal: true,
|
showTotal: true,
|
||||||
|
paginationTotalRenderer: customTotal,
|
||||||
sizePerPageList: [{
|
sizePerPageList: [{
|
||||||
text: '5', value: 5
|
text: '5', value: 5
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
107
packages/react-bootstrap-table2-example/examples/row-selection/custom-selection.js
vendored
Normal file
107
packages/react-bootstrap-table2-example/examples/row-selection/custom-selection.js
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/* eslint react/prop-types: 0 */
|
||||||
|
/* eslint no-param-reassign: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const selectRow1 = {
|
||||||
|
mode: 'radio',
|
||||||
|
clickToSelect: true,
|
||||||
|
selectionHeaderRenderer: () => 'X',
|
||||||
|
selectionRenderer: ({ mode, ...rest }) => (
|
||||||
|
<input type={ mode } { ...rest } />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectRow2 = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true,
|
||||||
|
selectionHeaderRenderer: ({ indeterminate, ...rest }) => (
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
ref={ (input) => {
|
||||||
|
if (input) input.indeterminate = indeterminate;
|
||||||
|
} }
|
||||||
|
{ ...rest }
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
selectionRenderer: ({ mode, ...rest }) => (
|
||||||
|
<input type={ mode } { ...rest } />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode1 = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
|
||||||
|
const columns = ....;
|
||||||
|
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'radio',
|
||||||
|
clickToSelect: true,
|
||||||
|
selectionHeaderRenderer: () => 'X',
|
||||||
|
selectionRenderer: ({ mode, ...rest }) => (
|
||||||
|
<input type={ mode } { ...rest } />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField='id'
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
selectRow={ selectRow }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const sourceCode2 = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
|
||||||
|
const columns = ....;
|
||||||
|
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true,
|
||||||
|
selectionHeaderRenderer: ({ indeterminate, ...rest }) => (
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
ref={ (input) => {
|
||||||
|
if (input) input.indeterminate = indeterminate;
|
||||||
|
} }
|
||||||
|
{ ...rest }
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
selectionRenderer: ({ mode, ...rest }) => (
|
||||||
|
<input type={ mode } { ...rest } />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField='id'
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
selectRow={ selectRow }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
|
||||||
|
<Code>{ sourceCode1 }</Code>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
|
||||||
|
<Code>{ sourceCode2 }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-example",
|
"name": "react-bootstrap-table2-example",
|
||||||
"version": "0.1.8",
|
"version": "0.1.12",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import HeaderColumnEventTable from 'examples/header-columns/column-event-table';
|
|||||||
import HeaderColumnClassTable from 'examples/header-columns/column-class-table';
|
import HeaderColumnClassTable from 'examples/header-columns/column-class-table';
|
||||||
import HeaderColumnStyleTable from 'examples/header-columns/column-style-table';
|
import HeaderColumnStyleTable from 'examples/header-columns/column-style-table';
|
||||||
import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
|
import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
|
||||||
|
import HeaderClassTable from 'examples/header-columns/header-class-table';
|
||||||
|
|
||||||
// column filter
|
// column filter
|
||||||
import TextFilter from 'examples/column-filter/text-filter';
|
import TextFilter from 'examples/column-filter/text-filter';
|
||||||
@@ -45,12 +46,22 @@ import SelectFilter from 'examples/column-filter/select-filter';
|
|||||||
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
|
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
|
||||||
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
|
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
|
||||||
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
|
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
|
||||||
|
import MultiSelectFilter from 'examples/column-filter/multi-select-filter';
|
||||||
|
import MultiSelectFilterDefaultValue from 'examples/column-filter/multi-select-filter-default-value';
|
||||||
|
import CustomMultiSelectFilter from 'examples/column-filter/custom-multi-select-filter';
|
||||||
import NumberFilter from 'examples/column-filter/number-filter';
|
import NumberFilter from 'examples/column-filter/number-filter';
|
||||||
import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value';
|
import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value';
|
||||||
import CustomNumberFilter from 'examples/column-filter/custom-number-filter';
|
import CustomNumberFilter from 'examples/column-filter/custom-number-filter';
|
||||||
|
import DateFilter from 'examples/column-filter/date-filter';
|
||||||
|
import DateFilterWithDefaultValue from 'examples/column-filter/date-filter-default-value';
|
||||||
|
import CustomDateFilter from 'examples/column-filter/custom-date-filter';
|
||||||
import ProgrammaticallyTextFilter from 'examples/column-filter/programmatically-text-filter';
|
import ProgrammaticallyTextFilter from 'examples/column-filter/programmatically-text-filter';
|
||||||
import ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter';
|
import ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter';
|
||||||
import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter';
|
import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter';
|
||||||
|
import ProgrammaticallyDateFilter from 'examples/column-filter/programmatically-date-filter';
|
||||||
|
import ProgrammaticallyMultiSelectFilter from 'examples/column-filter/programmatically-multi-select-filter';
|
||||||
|
import CustomFilter from 'examples/column-filter/custom-filter';
|
||||||
|
import AdvanceCustomFilter from 'examples/column-filter/advance-custom-filter';
|
||||||
|
|
||||||
// work on rows
|
// work on rows
|
||||||
import RowStyleTable from 'examples/rows/row-style';
|
import RowStyleTable from 'examples/rows/row-style';
|
||||||
@@ -95,6 +106,7 @@ import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-sele
|
|||||||
import SelectionNoDataTable from 'examples/row-selection/selection-no-data';
|
import SelectionNoDataTable from 'examples/row-selection/selection-no-data';
|
||||||
import SelectionStyleTable from 'examples/row-selection/selection-style';
|
import SelectionStyleTable from 'examples/row-selection/selection-style';
|
||||||
import SelectionClassTable from 'examples/row-selection/selection-class';
|
import SelectionClassTable from 'examples/row-selection/selection-class';
|
||||||
|
import CustomSelectionTable from 'examples/row-selection/custom-selection';
|
||||||
import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows';
|
import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows';
|
||||||
import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor';
|
import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor';
|
||||||
import SelectionHooks from 'examples/row-selection/selection-hooks';
|
import SelectionHooks from 'examples/row-selection/selection-hooks';
|
||||||
@@ -158,7 +170,8 @@ storiesOf('Work on Header Columns', module)
|
|||||||
.add('Column Event', () => <HeaderColumnEventTable />)
|
.add('Column Event', () => <HeaderColumnEventTable />)
|
||||||
.add('Customize Column Class', () => <HeaderColumnClassTable />)
|
.add('Customize Column Class', () => <HeaderColumnClassTable />)
|
||||||
.add('Customize Column Style', () => <HeaderColumnStyleTable />)
|
.add('Customize Column Style', () => <HeaderColumnStyleTable />)
|
||||||
.add('Customize Column HTML attribute', () => <HeaderColumnAttrsTable />);
|
.add('Customize Column HTML attribute', () => <HeaderColumnAttrsTable />)
|
||||||
|
.add('Header Class', () => <HeaderClassTable />);
|
||||||
|
|
||||||
storiesOf('Column Filter', module)
|
storiesOf('Column Filter', module)
|
||||||
.add('Text Filter', () => <TextFilter />)
|
.add('Text Filter', () => <TextFilter />)
|
||||||
@@ -169,15 +182,25 @@ storiesOf('Column Filter', module)
|
|||||||
.add('Select Filter', () => <SelectFilter />)
|
.add('Select Filter', () => <SelectFilter />)
|
||||||
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
|
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
|
||||||
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
|
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
|
||||||
|
.add('MultiSelect Filter', () => <MultiSelectFilter />)
|
||||||
|
.add('MultiSelect Filter with Default Value', () => <MultiSelectFilterDefaultValue />)
|
||||||
.add('Number Filter', () => <NumberFilter />)
|
.add('Number Filter', () => <NumberFilter />)
|
||||||
.add('Number Filter with Default Value', () => <NumberFilterWithDefaultValue />)
|
.add('Number Filter with Default Value', () => <NumberFilterWithDefaultValue />)
|
||||||
|
.add('Date Filter', () => <DateFilter />)
|
||||||
|
.add('Date Filter with Default Value', () => <DateFilterWithDefaultValue />)
|
||||||
.add('Custom Text Filter', () => <CustomTextFilter />)
|
.add('Custom Text Filter', () => <CustomTextFilter />)
|
||||||
.add('Custom Select Filter', () => <CustomSelectFilter />)
|
.add('Custom Select Filter', () => <CustomSelectFilter />)
|
||||||
.add('Custom Number Filter', () => <CustomNumberFilter />)
|
.add('Custom Number Filter', () => <CustomNumberFilter />)
|
||||||
|
.add('Custom Date Filter', () => <CustomDateFilter />)
|
||||||
|
.add('Custom MultiSelect Filter', () => <CustomMultiSelectFilter />)
|
||||||
.add('Custom Filter Value', () => <CustomFilterValue />)
|
.add('Custom Filter Value', () => <CustomFilterValue />)
|
||||||
.add('Programmatically Text Filter ', () => <ProgrammaticallyTextFilter />)
|
.add('Programmatically Text Filter', () => <ProgrammaticallyTextFilter />)
|
||||||
.add('Programmatically Select Filter ', () => <ProgrammaticallySelectFilter />)
|
.add('Programmatically Select Filter', () => <ProgrammaticallySelectFilter />)
|
||||||
.add('Programmatically Number Filter ', () => <ProgrammaticallyNumberFilter />);
|
.add('Programmatically Number Filter', () => <ProgrammaticallyNumberFilter />)
|
||||||
|
.add('Programmatically Date Filter', () => <ProgrammaticallyDateFilter />)
|
||||||
|
.add('Programmatically Multi Select Filter', () => <ProgrammaticallyMultiSelectFilter />)
|
||||||
|
.add('Custom Filter', () => <CustomFilter />)
|
||||||
|
.add('Advance Custom Filter', () => <AdvanceCustomFilter />);
|
||||||
|
|
||||||
storiesOf('Work on Rows', module)
|
storiesOf('Work on Rows', module)
|
||||||
.add('Customize Row Style', () => <RowStyleTable />)
|
.add('Customize Row Style', () => <RowStyleTable />)
|
||||||
@@ -222,6 +245,7 @@ storiesOf('Row Selection', module)
|
|||||||
.add('Selection without Data', () => <SelectionNoDataTable />)
|
.add('Selection without Data', () => <SelectionNoDataTable />)
|
||||||
.add('Selection Style', () => <SelectionStyleTable />)
|
.add('Selection Style', () => <SelectionStyleTable />)
|
||||||
.add('Selection Class', () => <SelectionClassTable />)
|
.add('Selection Class', () => <SelectionClassTable />)
|
||||||
|
.add('Custom Selection', () => <CustomSelectionTable />)
|
||||||
.add('Selection Background Color', () => <SelectionBgColorTable />)
|
.add('Selection Background Color', () => <SelectionBgColorTable />)
|
||||||
.add('Not Selectabled Rows', () => <NonSelectableRowsTable />)
|
.add('Not Selectabled Rows', () => <NonSelectableRowsTable />)
|
||||||
.add('Selection Hooks', () => <SelectionHooks />)
|
.add('Selection Hooks', () => <SelectionHooks />)
|
||||||
|
|||||||
@@ -9,4 +9,8 @@
|
|||||||
|
|
||||||
.demo-row-odd {
|
.demo-row-odd {
|
||||||
background-color: $green-lighten-4;
|
background-color: $green-lighten-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-class {
|
||||||
|
background-color: $green-lighten-4;
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,10 @@ You can get all types of filters via import and these filters are a factory func
|
|||||||
|
|
||||||
* TextFilter
|
* TextFilter
|
||||||
* SelectFilter
|
* SelectFilter
|
||||||
|
* MultiSelectFilter
|
||||||
* NumberFilter
|
* NumberFilter
|
||||||
|
* DateFilter
|
||||||
|
* CustomFilter
|
||||||
* **Coming soon!**
|
* **Coming soon!**
|
||||||
|
|
||||||
## Add CSS
|
## Add CSS
|
||||||
@@ -112,6 +115,52 @@ const qualityFilter = selectFilter({
|
|||||||
// omit...
|
// omit...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## MultiSelect Filter
|
||||||
|
|
||||||
|
A quick example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { multiSelectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
// omit...
|
||||||
|
const selectOptions = {
|
||||||
|
0: 'good',
|
||||||
|
1: 'Bad',
|
||||||
|
2: 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quailty',
|
||||||
|
formatter: cell => selectOptions[cell],
|
||||||
|
filter: multiSelectFilter({
|
||||||
|
options: selectOptions
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
```
|
||||||
|
|
||||||
|
Following is an example for custom select filter:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { multiSelectFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
// omit...
|
||||||
|
|
||||||
|
const qualityFilter = multiSelectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
placeholder: 'My Custom PlaceHolder', // custom the input placeholder
|
||||||
|
className: 'my-custom-text-filter', // custom classname on input
|
||||||
|
defaultValue: '2', // default filtering value
|
||||||
|
comparator: Comparator.LIKE, // default is Comparator.EQ
|
||||||
|
style: { ... }, // your custom styles on input
|
||||||
|
withoutEmptyOption: true // hide the default select option
|
||||||
|
});
|
||||||
|
|
||||||
|
// omit...
|
||||||
|
```
|
||||||
|
|
||||||
## Number Filter
|
## Number Filter
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -129,7 +178,7 @@ const columns = [..., {
|
|||||||
Numner filter is same as other filter, you can custom the number filter via `numberFilter` factory function:
|
Numner filter is same as other filter, you can custom the number filter via `numberFilter` factory function:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
|
import filterFactory, { selectFilter, Comparator, numberFilter } from 'react-bootstrap-table2-filter';
|
||||||
// omit...
|
// omit...
|
||||||
|
|
||||||
const numberFilter = numberFilter({
|
const numberFilter = numberFilter({
|
||||||
@@ -149,4 +198,93 @@ const numberFilter = numberFilter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// omit...
|
// omit...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Date Filter
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [..., {
|
||||||
|
dataField: 'date',
|
||||||
|
text: 'Product date',
|
||||||
|
filter: dateFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Notes:** date filter accept a Javascript Date object in your raw data.
|
||||||
|
|
||||||
|
Date filter is same as other filter, you can custom the date filter via `dateFilter` factory function:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
// omit...
|
||||||
|
|
||||||
|
const dateFilter = dateFilter({
|
||||||
|
delay: 600, // how long will trigger filtering after user typing, default is 500 ms
|
||||||
|
placeholder: 'custom placeholder', // placeholder for date input
|
||||||
|
withoutEmptyComparatorOption: true, // dont render empty option for comparator
|
||||||
|
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators
|
||||||
|
style: { display: 'inline-grid' }, // custom the style on date filter
|
||||||
|
className: 'custom-dateFilter-class', // custom the class on date filter
|
||||||
|
comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select
|
||||||
|
comparatorClassName: 'custom-comparator-class', // custom the class on comparator select
|
||||||
|
dateStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on date input
|
||||||
|
dateClassName: 'custom-date-class', // custom the class on date input
|
||||||
|
defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT } // default value
|
||||||
|
})
|
||||||
|
|
||||||
|
// omit...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Filter
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { customFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [..., {
|
||||||
|
dataField: 'date',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: customFilter(),
|
||||||
|
filterRenderer: (onFilter, column) => .....
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
```
|
||||||
|
|
||||||
|
In custom filter case, you are suppose to finish following two steps:
|
||||||
|
1. Call `customFilter` and pass to `column.filter`
|
||||||
|
2. Give `column.filterRenderer` as a callback function and return your custom filter element.
|
||||||
|
|
||||||
|
### column.filterRenderer
|
||||||
|
|
||||||
|
This function will pass two argument to you:
|
||||||
|
1. `onFilter`: call it to trigger filter when you need.
|
||||||
|
2. `column`: Just the column object!
|
||||||
|
|
||||||
|
In the end, please remember to return your custom filter element!
|
||||||
|
|
||||||
|
### customFilter
|
||||||
|
|
||||||
|
`customFilter` function just same as `textFilter`, `selectFilter` etc, it is for customization reason. However, in the custom filter case, there's only one props is valid: `type`
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { FILTER_TYPES } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const customFilter = customFilter({
|
||||||
|
type: FILTER_TYPES.NUMBER, // default is FILTER_TYPES.TEXT
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
`type` is a way to ask `react-bootstrap-table` to filter you data as number, select, date or normal text.
|
||||||
|
|
||||||
|
### FILTER_TYPES
|
||||||
|
|
||||||
|
Following properties is valid in `FILTER_TYPES`:
|
||||||
|
* TEXT
|
||||||
|
* SELECT
|
||||||
|
* NUMBER
|
||||||
|
* DATE
|
||||||
|
|||||||
19
packages/react-bootstrap-table2-filter/index.js
vendored
19
packages/react-bootstrap-table2-filter/index.js
vendored
@@ -1,14 +1,19 @@
|
|||||||
import TextFilter from './src/components/text';
|
import TextFilter from './src/components/text';
|
||||||
import SelectFilter from './src/components/select';
|
import SelectFilter from './src/components/select';
|
||||||
|
import MultiSelectFilter from './src/components/multiselect';
|
||||||
import NumberFilter from './src/components/number';
|
import NumberFilter from './src/components/number';
|
||||||
|
import DateFilter from './src/components/date';
|
||||||
import wrapperFactory from './src/wrapper';
|
import wrapperFactory from './src/wrapper';
|
||||||
import * as Comparison from './src/comparison';
|
import * as Comparison from './src/comparison';
|
||||||
|
import { FILTER_TYPE } from './src/const';
|
||||||
|
|
||||||
export default (options = {}) => ({
|
export default (options = {}) => ({
|
||||||
wrapperFactory,
|
wrapperFactory,
|
||||||
options
|
options
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const FILTER_TYPES = FILTER_TYPE;
|
||||||
|
|
||||||
export const Comparator = Comparison;
|
export const Comparator = Comparison;
|
||||||
|
|
||||||
export const textFilter = (props = {}) => ({
|
export const textFilter = (props = {}) => ({
|
||||||
@@ -21,7 +26,21 @@ export const selectFilter = (props = {}) => ({
|
|||||||
props
|
props
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const multiSelectFilter = (props = {}) => ({
|
||||||
|
Filter: MultiSelectFilter,
|
||||||
|
props
|
||||||
|
});
|
||||||
|
|
||||||
export const numberFilter = (props = {}) => ({
|
export const numberFilter = (props = {}) => ({
|
||||||
Filter: NumberFilter,
|
Filter: NumberFilter,
|
||||||
props
|
props
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const dateFilter = (props = {}) => ({
|
||||||
|
Filter: DateFilter,
|
||||||
|
props
|
||||||
|
});
|
||||||
|
|
||||||
|
export const customFilter = (props = {}) => ({
|
||||||
|
props
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-filter",
|
"name": "react-bootstrap-table2-filter",
|
||||||
"version": "0.1.7",
|
"version": "0.3.2",
|
||||||
"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": {
|
||||||
|
|||||||
213
packages/react-bootstrap-table2-filter/src/components/date.js
vendored
Normal file
213
packages/react-bootstrap-table2-filter/src/components/date.js
vendored
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
/* eslint react/require-default-props: 0 */
|
||||||
|
/* eslint jsx-a11y/no-static-element-interactions: 0 */
|
||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
/* eslint prefer-template: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { PropTypes } from 'prop-types';
|
||||||
|
|
||||||
|
import * as Comparator from '../comparison';
|
||||||
|
import { FILTER_TYPE } from '../const';
|
||||||
|
|
||||||
|
const legalComparators = [
|
||||||
|
Comparator.EQ,
|
||||||
|
Comparator.NE,
|
||||||
|
Comparator.GT,
|
||||||
|
Comparator.GE,
|
||||||
|
Comparator.LT,
|
||||||
|
Comparator.LE
|
||||||
|
];
|
||||||
|
|
||||||
|
function dateParser(d) {
|
||||||
|
return `${d.getFullYear()}-${('0' + (d.getMonth() + 1)).slice(-2)}-${('0' + d.getDate()).slice(-2)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DateFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.timeout = null;
|
||||||
|
this.comparators = props.comparators || legalComparators;
|
||||||
|
this.applyFilter = this.applyFilter.bind(this);
|
||||||
|
this.onChangeDate = this.onChangeDate.bind(this);
|
||||||
|
this.onChangeComparator = this.onChangeComparator.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { getFilter } = this.props;
|
||||||
|
const comparator = this.dateFilterComparator.value;
|
||||||
|
const date = this.inputDate.value;
|
||||||
|
if (comparator && date) {
|
||||||
|
this.applyFilter(date, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export onFilter function to allow users to access
|
||||||
|
if (getFilter) {
|
||||||
|
getFilter((filterVal) => {
|
||||||
|
this.dateFilterComparator.value = filterVal.comparator;
|
||||||
|
this.inputDate.value = dateParser(filterVal.date);
|
||||||
|
|
||||||
|
this.applyFilter(filterVal.date, filterVal.comparator);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.timeout) clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeDate(e) {
|
||||||
|
const comparator = this.dateFilterComparator.value;
|
||||||
|
const filterValue = e.target.value;
|
||||||
|
this.applyFilter(filterValue, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeComparator(e) {
|
||||||
|
const value = this.inputDate.value;
|
||||||
|
const comparator = e.target.value;
|
||||||
|
this.applyFilter(value, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
getComparatorOptions() {
|
||||||
|
const optionTags = [];
|
||||||
|
const { withoutEmptyComparatorOption } = this.props;
|
||||||
|
if (!withoutEmptyComparatorOption) {
|
||||||
|
optionTags.push(<option key="-1" />);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.comparators.length; i += 1) {
|
||||||
|
optionTags.push(
|
||||||
|
<option key={ i } value={ this.comparators[i] }>
|
||||||
|
{ this.comparators[i] }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return optionTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultDate() {
|
||||||
|
let defaultDate = '';
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
if (defaultValue && defaultValue.date) {
|
||||||
|
// Set the appropriate format for the input type=date, i.e. "YYYY-MM-DD"
|
||||||
|
defaultDate = dateParser(new Date(defaultValue.date));
|
||||||
|
}
|
||||||
|
return defaultDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(value, comparator) {
|
||||||
|
// if (!comparator || !value) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
const { column, onFilter, delay } = this.props;
|
||||||
|
const execute = () => {
|
||||||
|
// Incoming value should always be a string, and the defaultDate
|
||||||
|
// above is implemented as an empty string, so we can just check for that.
|
||||||
|
// instead of parsing an invalid Date. The filter function will interpret
|
||||||
|
// null as an empty date field
|
||||||
|
const date = value === '' ? null : new Date(value);
|
||||||
|
onFilter(column, FILTER_TYPE.DATE)({ date, comparator });
|
||||||
|
};
|
||||||
|
if (delay) {
|
||||||
|
this.timeout = setTimeout(() => { execute(); }, delay);
|
||||||
|
} else {
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
placeholder,
|
||||||
|
column: { text },
|
||||||
|
style,
|
||||||
|
comparatorStyle,
|
||||||
|
dateStyle,
|
||||||
|
className,
|
||||||
|
comparatorClassName,
|
||||||
|
dateClassName,
|
||||||
|
defaultValue
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
|
className={ `filter date-filter ${className}` }
|
||||||
|
style={ style }
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
ref={ n => this.dateFilterComparator = n }
|
||||||
|
style={ comparatorStyle }
|
||||||
|
className={ `date-filter-comparator form-control ${comparatorClassName}` }
|
||||||
|
onChange={ this.onChangeComparator }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.comparator : '' }
|
||||||
|
>
|
||||||
|
{ this.getComparatorOptions() }
|
||||||
|
</select>
|
||||||
|
<input
|
||||||
|
ref={ n => this.inputDate = n }
|
||||||
|
className={ `filter date-filter-input form-control ${dateClassName}` }
|
||||||
|
style={ dateStyle }
|
||||||
|
type="date"
|
||||||
|
onChange={ this.onChangeDate }
|
||||||
|
placeholder={ placeholder || `Enter ${text}...` }
|
||||||
|
defaultValue={ this.getDefaultDate() }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateFilter.propTypes = {
|
||||||
|
onFilter: PropTypes.func.isRequired,
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
delay: PropTypes.number,
|
||||||
|
defaultValue: PropTypes.shape({
|
||||||
|
date: PropTypes.oneOfType([PropTypes.object]),
|
||||||
|
comparator: PropTypes.oneOf([...legalComparators, ''])
|
||||||
|
}),
|
||||||
|
/* eslint consistent-return: 0 */
|
||||||
|
comparators: (props, propName) => {
|
||||||
|
if (!props[propName]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < props[propName].length; i += 1) {
|
||||||
|
let comparatorIsValid = false;
|
||||||
|
for (let j = 0; j < legalComparators.length; j += 1) {
|
||||||
|
if (legalComparators[j] === props[propName][i] || props[propName][i] === '') {
|
||||||
|
comparatorIsValid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!comparatorIsValid) {
|
||||||
|
return new Error(`Date comparator provided is not supported.
|
||||||
|
Use only ${legalComparators}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
withoutEmptyComparatorOption: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
comparatorStyle: PropTypes.object,
|
||||||
|
dateStyle: PropTypes.object,
|
||||||
|
className: PropTypes.string,
|
||||||
|
comparatorClassName: PropTypes.string,
|
||||||
|
dateClassName: PropTypes.string,
|
||||||
|
getFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
DateFilter.defaultProps = {
|
||||||
|
delay: 0,
|
||||||
|
defaultValue: {
|
||||||
|
date: undefined,
|
||||||
|
comparator: ''
|
||||||
|
},
|
||||||
|
withoutEmptyComparatorOption: false,
|
||||||
|
comparators: legalComparators,
|
||||||
|
placeholder: undefined,
|
||||||
|
style: undefined,
|
||||||
|
className: '',
|
||||||
|
comparatorStyle: undefined,
|
||||||
|
comparatorClassName: '',
|
||||||
|
dateStyle: undefined,
|
||||||
|
dateClassName: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default DateFilter;
|
||||||
152
packages/react-bootstrap-table2-filter/src/components/multiselect.js
vendored
Normal file
152
packages/react-bootstrap-table2-filter/src/components/multiselect.js
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/* eslint react/require-default-props: 0 */
|
||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
/* eslint no-param-reassign: 0 */
|
||||||
|
/* eslint react/no-unused-prop-types: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { LIKE, EQ } from '../comparison';
|
||||||
|
import { FILTER_TYPE } from '../const';
|
||||||
|
|
||||||
|
|
||||||
|
function optionsEquals(currOpts, prevOpts) {
|
||||||
|
const keys = Object.keys(currOpts);
|
||||||
|
for (let i = 0; i < keys.length; i += 1) {
|
||||||
|
if (currOpts[keys[i]] !== prevOpts[keys[i]]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Object.keys(currOpts).length === Object.keys(prevOpts).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelections = container =>
|
||||||
|
Array.from(container.selectedOptions).map(item => item.value);
|
||||||
|
|
||||||
|
class MultiSelectFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
this.applyFilter = this.applyFilter.bind(this);
|
||||||
|
const isSelected = props.defaultValue.map(item => props.options[item]).length > 0;
|
||||||
|
this.state = { isSelected };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { getFilter } = this.props;
|
||||||
|
|
||||||
|
const value = getSelections(this.selectInput);
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
this.applyFilter(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export onFilter function to allow users to access
|
||||||
|
if (getFilter) {
|
||||||
|
getFilter((filterVal) => {
|
||||||
|
this.selectInput.value = filterVal;
|
||||||
|
this.applyFilter(filterVal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
let needFilter = false;
|
||||||
|
if (this.props.defaultValue !== prevProps.defaultValue) {
|
||||||
|
needFilter = true;
|
||||||
|
} else if (!optionsEquals(this.props.options, prevProps.options)) {
|
||||||
|
needFilter = true;
|
||||||
|
}
|
||||||
|
if (needFilter) {
|
||||||
|
this.applyFilter(this.selectInput.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions() {
|
||||||
|
const optionTags = [];
|
||||||
|
const { options, placeholder, column, withoutEmptyOption } = this.props;
|
||||||
|
if (!withoutEmptyOption) {
|
||||||
|
optionTags.push((
|
||||||
|
<option key="-1" value="">{ placeholder || `Select ${column.text}...` }</option>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Object.keys(options).forEach(key =>
|
||||||
|
optionTags.push(<option key={ key } value={ key }>{ options[key] }</option>)
|
||||||
|
);
|
||||||
|
return optionTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanFiltered() {
|
||||||
|
const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : [];
|
||||||
|
this.selectInput.value = value;
|
||||||
|
this.applyFilter(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(value) {
|
||||||
|
if (value.length === 1 && value[0] === '') {
|
||||||
|
value = [];
|
||||||
|
}
|
||||||
|
this.setState(() => ({ isSelected: value.length > 0 }));
|
||||||
|
this.props.onFilter(this.props.column, FILTER_TYPE.MULTISELECT)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(e) {
|
||||||
|
const value = getSelections(e.target);
|
||||||
|
this.applyFilter(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
defaultValue,
|
||||||
|
onFilter,
|
||||||
|
column,
|
||||||
|
options,
|
||||||
|
comparator,
|
||||||
|
withoutEmptyOption,
|
||||||
|
caseSensitive,
|
||||||
|
getFilter,
|
||||||
|
...rest
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const selectClass =
|
||||||
|
`filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
{ ...rest }
|
||||||
|
ref={ n => this.selectInput = n }
|
||||||
|
style={ style }
|
||||||
|
multiple
|
||||||
|
className={ selectClass }
|
||||||
|
onChange={ this.filter }
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
|
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
|
||||||
|
>
|
||||||
|
{ this.getOptions() }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiSelectFilter.propTypes = {
|
||||||
|
onFilter: PropTypes.func.isRequired,
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
options: PropTypes.object.isRequired,
|
||||||
|
comparator: PropTypes.oneOf([LIKE, EQ]),
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
style: PropTypes.object,
|
||||||
|
className: PropTypes.string,
|
||||||
|
withoutEmptyOption: PropTypes.bool,
|
||||||
|
defaultValue: PropTypes.array,
|
||||||
|
caseSensitive: PropTypes.bool,
|
||||||
|
getFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiSelectFilter.defaultProps = {
|
||||||
|
defaultValue: [],
|
||||||
|
className: '',
|
||||||
|
withoutEmptyOption: false,
|
||||||
|
comparator: EQ,
|
||||||
|
caseSensitive: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MultiSelectFilter;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint jsx-a11y/no-static-element-interactions: 0 */
|
||||||
/* eslint react/require-default-props: 0 */
|
/* eslint react/require-default-props: 0 */
|
||||||
/* eslint no-return-assign: 0 */
|
/* eslint no-return-assign: 0 */
|
||||||
|
|
||||||
@@ -167,7 +168,11 @@ class NumberFilter extends Component {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ `filter number-filter ${className}` } style={ style }>
|
<div
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
|
className={ `filter number-filter ${className}` }
|
||||||
|
style={ style }
|
||||||
|
>
|
||||||
<select
|
<select
|
||||||
ref={ n => this.numberFilterComparator = n }
|
ref={ n => this.numberFilterComparator = n }
|
||||||
style={ comparatorStyle }
|
style={ comparatorStyle }
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ class SelectFilter extends Component {
|
|||||||
style={ style }
|
style={ style }
|
||||||
className={ selectClass }
|
className={ selectClass }
|
||||||
onChange={ this.filter }
|
onChange={ this.filter }
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
|
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
|
||||||
>
|
>
|
||||||
{ this.getOptions() }
|
{ this.getOptions() }
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
export const FILTER_TYPE = {
|
export const FILTER_TYPE = {
|
||||||
TEXT: 'TEXT',
|
TEXT: 'TEXT',
|
||||||
SELECT: 'SELECT',
|
SELECT: 'SELECT',
|
||||||
NUMBER: 'NUMBER'
|
MULTISELECT: 'MULTISELECT',
|
||||||
|
NUMBER: 'NUMBER',
|
||||||
|
DATE: 'DATE'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FILTER_DELAY = 500;
|
export const FILTER_DELAY = 500;
|
||||||
|
|||||||
122
packages/react-bootstrap-table2-filter/src/filter.js
vendored
122
packages/react-bootstrap-table2-filter/src/filter.js
vendored
@@ -91,6 +91,122 @@ export const filterByNumber = _ => (
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const filterByDate = _ => (
|
||||||
|
data,
|
||||||
|
dataField,
|
||||||
|
{ filterVal: { comparator, date } },
|
||||||
|
customFilterValue
|
||||||
|
) => {
|
||||||
|
if (!date || !comparator) return data;
|
||||||
|
const filterDate = date.getDate();
|
||||||
|
const filterMonth = date.getMonth();
|
||||||
|
const filterYear = date.getFullYear();
|
||||||
|
|
||||||
|
return data.filter((row) => {
|
||||||
|
let valid = true;
|
||||||
|
let cell = _.get(row, dataField);
|
||||||
|
|
||||||
|
if (customFilterValue) {
|
||||||
|
cell = customFilterValue(cell, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
cell = new Date(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetDate = cell.getDate();
|
||||||
|
const targetMonth = cell.getMonth();
|
||||||
|
const targetYear = cell.getFullYear();
|
||||||
|
|
||||||
|
|
||||||
|
switch (comparator) {
|
||||||
|
case EQ: {
|
||||||
|
if (
|
||||||
|
filterDate !== targetDate ||
|
||||||
|
filterMonth !== targetMonth ||
|
||||||
|
filterYear !== targetYear
|
||||||
|
) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GT: {
|
||||||
|
if (cell <= date) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GE: {
|
||||||
|
if (targetYear < filterYear) {
|
||||||
|
valid = false;
|
||||||
|
} else if (targetYear === filterYear &&
|
||||||
|
targetMonth < filterMonth) {
|
||||||
|
valid = false;
|
||||||
|
} else if (targetYear === filterYear &&
|
||||||
|
targetMonth === filterMonth &&
|
||||||
|
targetDate < filterDate) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LT: {
|
||||||
|
if (cell >= date) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LE: {
|
||||||
|
if (targetYear > filterYear) {
|
||||||
|
valid = false;
|
||||||
|
} else if (targetYear === filterYear &&
|
||||||
|
targetMonth > filterMonth) {
|
||||||
|
valid = false;
|
||||||
|
} else if (targetYear === filterYear &&
|
||||||
|
targetMonth === filterMonth &&
|
||||||
|
targetDate > filterDate) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NE: {
|
||||||
|
if (
|
||||||
|
filterDate === targetDate &&
|
||||||
|
filterMonth === targetMonth &&
|
||||||
|
filterYear === targetYear
|
||||||
|
) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.error('Date comparator provided is not supported');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filterByArray = _ => (
|
||||||
|
data,
|
||||||
|
dataField,
|
||||||
|
{ filterVal, comparator }
|
||||||
|
) => {
|
||||||
|
if (filterVal.length === 0) return data;
|
||||||
|
const refinedFilterVal = filterVal
|
||||||
|
.filter(x => _.isDefined(x))
|
||||||
|
.map(x => x.toString());
|
||||||
|
return data.filter((row) => {
|
||||||
|
const cell = _.get(row, dataField);
|
||||||
|
let cellStr = _.isDefined(cell) ? cell.toString() : '';
|
||||||
|
if (comparator === EQ) {
|
||||||
|
return refinedFilterVal.indexOf(cellStr) !== -1;
|
||||||
|
}
|
||||||
|
cellStr = cellStr.toLocaleUpperCase();
|
||||||
|
return refinedFilterVal.some(item => cellStr.indexOf(item.toLocaleUpperCase()) !== -1);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const filterFactory = _ => (filterType) => {
|
export const filterFactory = _ => (filterType) => {
|
||||||
let filterFn;
|
let filterFn;
|
||||||
switch (filterType) {
|
switch (filterType) {
|
||||||
@@ -98,9 +214,15 @@ export const filterFactory = _ => (filterType) => {
|
|||||||
case FILTER_TYPE.SELECT:
|
case FILTER_TYPE.SELECT:
|
||||||
filterFn = filterByText(_);
|
filterFn = filterByText(_);
|
||||||
break;
|
break;
|
||||||
|
case FILTER_TYPE.MULTISELECT:
|
||||||
|
filterFn = filterByArray(_);
|
||||||
|
break;
|
||||||
case FILTER_TYPE.NUMBER:
|
case FILTER_TYPE.NUMBER:
|
||||||
filterFn = filterByNumber(_);
|
filterFn = filterByNumber(_);
|
||||||
break;
|
break;
|
||||||
|
case FILTER_TYPE.DATE:
|
||||||
|
filterFn = filterByDate(_);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
filterFn = filterByText(_);
|
filterFn = filterByText(_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export default (Base, {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = { currFilters: {}, isDataChanged: props.isDataChanged || false };
|
this.state = { currFilters: {}, isDataChanged: props.isDataChanged || false };
|
||||||
this.onFilter = this.onFilter.bind(this);
|
this.onFilter = this.onFilter.bind(this);
|
||||||
|
this.onExternalFilter = this.onExternalFilter.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps({ isDataChanged, store, columns }) {
|
componentWillReceiveProps({ isDataChanged, store, columns }) {
|
||||||
@@ -52,12 +53,20 @@ export default (Base, {
|
|||||||
const currFilters = Object.assign({}, store.filters);
|
const currFilters = Object.assign({}, store.filters);
|
||||||
const { dataField, filter } = column;
|
const { dataField, filter } = column;
|
||||||
|
|
||||||
if (!_.isDefined(filterVal) || filterVal === '') {
|
const needClearFilters =
|
||||||
|
!_.isDefined(filterVal) ||
|
||||||
|
filterVal === '' ||
|
||||||
|
filterVal.length === 0;
|
||||||
|
|
||||||
|
if (needClearFilters) {
|
||||||
delete currFilters[dataField];
|
delete currFilters[dataField];
|
||||||
} else {
|
} else {
|
||||||
// select default comparator is EQ, others are LIKE
|
// select default comparator is EQ, others are LIKE
|
||||||
const {
|
const {
|
||||||
comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE),
|
comparator = (
|
||||||
|
(filterType === FILTER_TYPE.SELECT) || (
|
||||||
|
filterType === FILTER_TYPE.MULTISELECT) ? EQ : LIKE
|
||||||
|
),
|
||||||
caseSensitive = false
|
caseSensitive = false
|
||||||
} = filter.props;
|
} = filter.props;
|
||||||
currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive };
|
currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive };
|
||||||
@@ -78,12 +87,19 @@ export default (Base, {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onExternalFilter(column, filterType) {
|
||||||
|
return (value) => {
|
||||||
|
this.onFilter(column, filterType)(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Base
|
<Base
|
||||||
{ ...this.props }
|
{ ...this.props }
|
||||||
data={ this.props.store.data }
|
data={ this.props.store.data }
|
||||||
onFilter={ this.onFilter }
|
onFilter={ this.onFilter }
|
||||||
|
onExternalFilter={ this.onExternalFilter }
|
||||||
isDataChanged={ this.state.isDataChanged }
|
isDataChanged={ this.state.isDataChanged }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
|
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
|
||||||
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected,
|
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected,
|
||||||
.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder,
|
.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder,
|
||||||
.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder {
|
.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter-input::-webkit-input-placeholder {
|
||||||
color: lightgrey;
|
color: lightgrey;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@@ -15,17 +16,20 @@
|
|||||||
font-style: initial;
|
font-style: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-bootstrap-table > table > thead > tr > th .number-filter {
|
.react-bootstrap-table > table > thead > tr > th .number-filter,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-bootstrap-table > table > thead > tr > th .number-filter-input {
|
.react-bootstrap-table > table > thead > tr > th .number-filter-input,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter-input {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
float: left;
|
float: left;
|
||||||
width: calc(100% - 67px - 5px);
|
width: calc(100% - 67px - 5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-bootstrap-table > table > thead > tr > th .number-filter-comparator {
|
.react-bootstrap-table > table > thead > tr > th .number-filter-comparator,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter-comparator {
|
||||||
width: 67px;
|
width: 67px;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
import 'jsdom-global/register';
|
||||||
|
import React from 'react';
|
||||||
|
import { mount } from 'enzyme';
|
||||||
|
import DateFilter from '../../src/components/date';
|
||||||
|
import { FILTER_TYPE } from '../../src/const';
|
||||||
|
import * as Comparator from '../../src/comparison';
|
||||||
|
|
||||||
|
|
||||||
|
describe('Date Filter', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
|
||||||
|
const onFilterFirstReturn = jest.fn();
|
||||||
|
const onFilter = jest.fn().mockReturnValue(onFilterFirstReturn);
|
||||||
|
|
||||||
|
const column = {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
onFilter.mockClear();
|
||||||
|
onFilterFirstReturn.mockClear();
|
||||||
|
|
||||||
|
// onFilter.returns(onFilterFirstReturn);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initialization', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter onFilter={ onFilter } column={ column } />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter-input')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter-comparator')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering comparator options correctly', () => {
|
||||||
|
const select = wrapper.find('select');
|
||||||
|
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length + 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when withoutEmptyComparatorOption prop is true', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
withoutEmptyComparatorOption
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering comparator options correctly', () => {
|
||||||
|
const select = wrapper.find('.date-filter-comparator');
|
||||||
|
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.date props is defined', () => {
|
||||||
|
const date = new Date(2018, 0, 1);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
defaultValue={ { date } }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering input successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
const input = wrapper.find('.date-filter-input');
|
||||||
|
expect(input).toHaveLength(1);
|
||||||
|
expect(input.props().defaultValue).toEqual(wrapper.instance().getDefaultDate());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.comparator props is defined', () => {
|
||||||
|
const comparator = Comparator.EQ;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
defaultValue={ { comparator } }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering comparator select successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
const select = wrapper.find('.date-filter-comparator');
|
||||||
|
expect(select).toHaveLength(1);
|
||||||
|
expect(select.props().defaultValue).toEqual(comparator);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when props.getFilter is defined', () => {
|
||||||
|
let programmaticallyFilter;
|
||||||
|
|
||||||
|
const comparator = Comparator.EQ;
|
||||||
|
const date = new Date(2018, 0, 1);
|
||||||
|
|
||||||
|
const getFilter = (filter) => {
|
||||||
|
programmaticallyFilter = filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter onFilter={ onFilter } column={ column } getFilter={ getFilter } />
|
||||||
|
);
|
||||||
|
|
||||||
|
programmaticallyFilter({ comparator, date });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do onFilter correctly when exported function was executed', () => {
|
||||||
|
expect(onFilter).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onFilter).toHaveBeenCalledWith(column, FILTER_TYPE.DATE);
|
||||||
|
expect(onFilterFirstReturn).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onFilterFirstReturn).toHaveBeenCalledWith({ comparator, date });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.number and defaultValue.comparator props are defined', () => {
|
||||||
|
let date;
|
||||||
|
let comparator;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
date = new Date();
|
||||||
|
comparator = Comparator.EQ;
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
defaultValue={ { date, comparator } }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter on componentDidMount', () => {
|
||||||
|
expect(onFilter).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onFilter).toHaveBeenCalledWith(column, FILTER_TYPE.DATE);
|
||||||
|
expect(onFilterFirstReturn).toHaveBeenCalledTimes(1);
|
||||||
|
// expect(onFilterFirstReturn).toHaveBeenCalledWith({ comparator, date });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when style props is defined', () => {
|
||||||
|
const style = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
style={ style }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter').prop('style')).toEqual(style);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when dateStyle props is defined', () => {
|
||||||
|
const dateStyle = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
dateStyle={ dateStyle }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter-input').prop('style')).toEqual(dateStyle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when comparatorStyle props is defined', () => {
|
||||||
|
const comparatorStyle = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
comparatorStyle={ comparatorStyle }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter-comparator').prop('style')).toEqual(comparatorStyle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when className props is defined', () => {
|
||||||
|
const className = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
className={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.hasClass(className)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when dateClassName props is defined', () => {
|
||||||
|
const className = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
dateClassName={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter-input').prop('className').indexOf(className) > -1).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when comparatorClassName props is defined', () => {
|
||||||
|
const className = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<DateFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
comparatorClassName={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.date-filter-comparator').prop('className').indexOf(className) > -1).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,354 @@
|
|||||||
|
import 'jsdom-global/register';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { mount } from 'enzyme';
|
||||||
|
import MultiSelectFilter from '../../src/components/multiselect';
|
||||||
|
import { FILTER_TYPE } from '../../src/const';
|
||||||
|
|
||||||
|
|
||||||
|
describe('Multi Select Filter', () => {
|
||||||
|
let wrapper;
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
// onFilter(x)(y) = filter result
|
||||||
|
const onFilter = sinon.stub();
|
||||||
|
const onFilterFirstReturn = sinon.stub();
|
||||||
|
|
||||||
|
const column = {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality'
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
0: 'Bad',
|
||||||
|
1: 'Good',
|
||||||
|
2: 'Unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
onFilter.reset();
|
||||||
|
onFilterFirstReturn.reset();
|
||||||
|
|
||||||
|
onFilter.returns(onFilterFirstReturn);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initialization', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter onFilter={ onFilter } column={ column } options={ options } />
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct state', () => {
|
||||||
|
expect(instance.state.isSelected).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('select')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.select-filter')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.placeholder-selected')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering select options correctly', () => {
|
||||||
|
const select = wrapper.find('select');
|
||||||
|
expect(select.find('option')).toHaveLength(Object.keys(options).length + 1);
|
||||||
|
expect(select.childAt(0).text()).toEqual(`Select ${column.text}...`);
|
||||||
|
|
||||||
|
Object.keys(options).forEach((key, i) => {
|
||||||
|
expect(select.childAt(i + 1).prop('value')).toEqual(key);
|
||||||
|
expect(select.childAt(i + 1).text()).toEqual(options[key]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue is defined', () => {
|
||||||
|
let defaultValue;
|
||||||
|
|
||||||
|
describe('and it is valid', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
defaultValue = ['0'];
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct state', () => {
|
||||||
|
expect(instance.state.isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.placeholder-selected')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter on componentDidMount', () => {
|
||||||
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(defaultValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when props.getFilter is defined', () => {
|
||||||
|
let programmaticallyFilter;
|
||||||
|
|
||||||
|
const filterValue = ['foo'];
|
||||||
|
|
||||||
|
const getFilter = (filter) => {
|
||||||
|
programmaticallyFilter = filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
getFilter={ getFilter }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
|
||||||
|
programmaticallyFilter(filterValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do onFilter correctly when exported function was executed', () => {
|
||||||
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(filterValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setState correctly when exported function was executed', () => {
|
||||||
|
expect(instance.state.isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when placeholder is defined', () => {
|
||||||
|
const placeholder = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
placeholder={ placeholder }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
const select = wrapper.find('select');
|
||||||
|
expect(select.childAt(0).text()).toEqual(placeholder);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when style is defined', () => {
|
||||||
|
const style = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
style={ style }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('select').prop('style')).toEqual(style);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when withoutEmptyOption is defined', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
withoutEmptyOption
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering select without default empty option', () => {
|
||||||
|
const select = wrapper.find('select');
|
||||||
|
expect(select.find('option')).toHaveLength(Object.keys(options).length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('componentDidUpdate', () => {
|
||||||
|
let prevProps;
|
||||||
|
|
||||||
|
describe('when props.defaultValue is diff from prevProps.defaultValue', () => {
|
||||||
|
const defaultValue = ['0'];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
prevProps = {
|
||||||
|
column,
|
||||||
|
options,
|
||||||
|
defaultValue: ['1']
|
||||||
|
};
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.componentDidUpdate(prevProps);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update', () => {
|
||||||
|
expect(onFilter.callCount).toBe(2);
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||||
|
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when props.options is diff from prevProps.options', () => {
|
||||||
|
const defaultValue = ['0'];
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ {
|
||||||
|
...options,
|
||||||
|
3: 'Best'
|
||||||
|
} }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
prevProps = {
|
||||||
|
column,
|
||||||
|
options
|
||||||
|
};
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.componentDidUpdate(prevProps);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update', () => {
|
||||||
|
expect(onFilter.callCount).toBe(2);
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||||
|
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cleanFiltered', () => {
|
||||||
|
describe('when props.defaultValue is defined', () => {
|
||||||
|
const defaultValue = ['0'];
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.cleanFiltered();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setting state correctly', () => {
|
||||||
|
expect(instance.state.isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter correctly', () => {
|
||||||
|
expect(onFilter.callCount).toBe(2);
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||||
|
expect(onFilterFirstReturn.calledWith(defaultValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when props.defaultValue is not defined', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.cleanFiltered();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setting state correctly', () => {
|
||||||
|
expect(instance.state.isSelected).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter correctly', () => {
|
||||||
|
expect(onFilter.callCount).toBe(1);
|
||||||
|
expect(onFilterFirstReturn.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('applyFilter', () => {
|
||||||
|
const values = ['2'];
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter onFilter={ onFilter } column={ column } options={ options } />
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.applyFilter(values);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setting state correctly', () => {
|
||||||
|
expect(instance.state.isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter correctly', () => {
|
||||||
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(values)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('filter', () => {
|
||||||
|
const event = { target: { selectedOptions: [{ value: 'tester' }] } };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<MultiSelectFilter onFilter={ onFilter } column={ column } options={ options } />
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.filter(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setting state correctly', () => {
|
||||||
|
expect(instance.state.isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter correctly', () => {
|
||||||
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.MULTISELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(
|
||||||
|
event.target.selectedOptions.map(item => item.value))).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import sinon from 'sinon';
|
|
||||||
import _ from 'react-bootstrap-table-next/src/utils';
|
import _ from 'react-bootstrap-table-next/src/utils';
|
||||||
import Store from 'react-bootstrap-table-next/src/store';
|
import Store from 'react-bootstrap-table-next/src/store';
|
||||||
|
|
||||||
@@ -11,7 +10,8 @@ for (let i = 0; i < 20; i += 1) {
|
|||||||
data.push({
|
data.push({
|
||||||
id: i,
|
id: i,
|
||||||
name: `itme name ${i}`,
|
name: `itme name ${i}`,
|
||||||
price: 200 + i
|
price: 200 + i,
|
||||||
|
date: new Date(2017, i, 1)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +34,9 @@ describe('filter', () => {
|
|||||||
}, {
|
}, {
|
||||||
dataField: 'price',
|
dataField: 'price',
|
||||||
text: 'Price'
|
text: 'Price'
|
||||||
|
}, {
|
||||||
|
dataField: 'date',
|
||||||
|
text: 'Date'
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -98,7 +101,7 @@ describe('filter', () => {
|
|||||||
|
|
||||||
describe('column.filterValue is defined', () => {
|
describe('column.filterValue is defined', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
columns[1].filterValue = sinon.stub();
|
columns[1].filterValue = jest.fn();
|
||||||
filterFn = filters(store, columns, _);
|
filterFn = filters(store, columns, _);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -110,10 +113,60 @@ describe('filter', () => {
|
|||||||
|
|
||||||
const result = filterFn(currFilters);
|
const result = filterFn(currFilters);
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
expect(columns[1].filterValue.callCount).toBe(data.length);
|
expect(columns[1].filterValue).toHaveBeenCalledTimes(data.length);
|
||||||
const calls = columns[1].filterValue.getCalls();
|
// const calls = columns[1].filterValue.mock.calls;
|
||||||
calls.forEach((call, i) => {
|
// calls.forEach((call, i) => {
|
||||||
expect(call.calledWith(data[i].name, data[i])).toBeTruthy();
|
// expect(call).toEqual([data[i].name, data[i]]);
|
||||||
|
// expect(call.calledWith(data[i].name, data[i])).toBeTruthy();
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('filterByArray', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
filterFn = filters(store, columns, _);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when filter value is empty array', () => {
|
||||||
|
it('should return original data', () => {
|
||||||
|
currFilters.name = {
|
||||||
|
filterVal: [],
|
||||||
|
filterType: FILTER_TYPE.MULTISELECT
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result).toHaveLength(store.data.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when filter value is not an empty array', () => {
|
||||||
|
describe(`and comparator is ${EQ}`, () => {
|
||||||
|
it('should return data correctly', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: [201, 203],
|
||||||
|
filterType: FILTER_TYPE.MULTISELECT,
|
||||||
|
comparator: EQ
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`and comparator is ${LIKE}`, () => {
|
||||||
|
it('should return data correctly', () => {
|
||||||
|
currFilters.name = {
|
||||||
|
filterVal: ['name 3', '5'],
|
||||||
|
filterType: FILTER_TYPE.MULTISELECT,
|
||||||
|
comparator: LIKE
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result).toHaveLength(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -228,4 +281,40 @@ describe('filter', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('filterByDate', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
filterFn = filters(store, columns, _);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when currFilters.filterVal.comparator is empty', () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: '', date: new Date() },
|
||||||
|
filterType: FILTER_TYPE.DATE
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(data.length);
|
||||||
|
|
||||||
|
currFilters.price.filterVal.comparator = undefined;
|
||||||
|
result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(data.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when currFilters.filterVal.date is empty', () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: EQ, date: '' },
|
||||||
|
filterType: FILTER_TYPE.DATE
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(data.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO....
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when filterVal is empty or undefined', () => {
|
describe('when filterVal is empty or undefined', () => {
|
||||||
const filterVals = ['', undefined];
|
const filterVals = ['', undefined, []];
|
||||||
|
|
||||||
it('should setting store object correctly', () => {
|
it('should setting store object correctly', () => {
|
||||||
filterVals.forEach((filterVal) => {
|
filterVals.forEach((filterVal) => {
|
||||||
|
|||||||
19
packages/react-bootstrap-table2-overlay/index.js
vendored
19
packages/react-bootstrap-table2-overlay/index.js
vendored
@@ -1,16 +1,29 @@
|
|||||||
/* eslint no-return-assign: 0 */
|
/* eslint no-return-assign: 0 */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import LoadingOverlay from 'react-loading-overlay';
|
import LoadingOverlay from 'react-loading-overlay';
|
||||||
|
|
||||||
export default options => (element, loading) =>
|
export default options => loading =>
|
||||||
class TableLoadingOverlayWrapper extends React.Component {
|
class TableLoadingOverlayWrapper extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.element.isRequired
|
||||||
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
const { wrapper } = this.overlay;
|
const { wrapper } = this.overlay;
|
||||||
const masker = wrapper.firstChild;
|
const masker = wrapper.firstChild;
|
||||||
const headerDOM = wrapper.parentElement.querySelector('thead');
|
const headerDOM = wrapper.parentElement.querySelector('thead');
|
||||||
const bodyDOM = wrapper.parentElement.querySelector('tbody');
|
const bodyDOM = wrapper.parentElement.querySelector('tbody');
|
||||||
masker.style.marginTop = window.getComputedStyle(headerDOM).height;
|
const captionDOM = wrapper.parentElement.querySelector('caption');
|
||||||
|
|
||||||
|
let marginTop = window.getComputedStyle(headerDOM).height;
|
||||||
|
if (captionDOM) {
|
||||||
|
marginTop = parseFloat(marginTop.replace('px', ''));
|
||||||
|
marginTop += parseFloat(window.getComputedStyle(captionDOM).height.replace('px', ''));
|
||||||
|
marginTop = `${marginTop}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
masker.style.marginTop = marginTop;
|
||||||
masker.style.height = window.getComputedStyle(bodyDOM).height;
|
masker.style.height = window.getComputedStyle(bodyDOM).height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +35,7 @@ export default options => (element, loading) =>
|
|||||||
{ ...options }
|
{ ...options }
|
||||||
active={ loading }
|
active={ loading }
|
||||||
>
|
>
|
||||||
{ element }
|
{ this.props.children }
|
||||||
</LoadingOverlay>
|
</LoadingOverlay>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-overlay",
|
"name": "react-bootstrap-table2-overlay",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"description": "it's a loading overlay addons for react-bootstrap-table2",
|
"description": "it's a loading overlay addons for react-bootstrap-table2",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow, render } from 'enzyme';
|
import { render, shallow } from 'enzyme';
|
||||||
import LoadingOverlay from 'react-loading-overlay';
|
import LoadingOverlay from 'react-loading-overlay';
|
||||||
|
|
||||||
import overlayFactory from '..';
|
import overlayFactory from '../index.js';
|
||||||
|
|
||||||
describe('overlayFactory', () => {
|
describe('overlayFactory', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
// let instance;
|
|
||||||
|
|
||||||
const createTable = () => (
|
const createTable = () => (
|
||||||
<table>
|
<table>
|
||||||
@@ -27,8 +26,8 @@ describe('overlayFactory', () => {
|
|||||||
describe('when loading is false', () => {
|
describe('when loading is false', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const tableElm = createTable();
|
const tableElm = createTable();
|
||||||
const Overlay = overlayFactory()(tableElm, false);
|
const Overlay = overlayFactory()(false);
|
||||||
wrapper = shallow(<Overlay />);
|
wrapper = shallow(<Overlay>{ tableElm }</Overlay>);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering Overlay component correctly', () => {
|
it('should rendering Overlay component correctly', () => {
|
||||||
@@ -42,14 +41,12 @@ describe('overlayFactory', () => {
|
|||||||
describe('when loading is true', () => {
|
describe('when loading is true', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const tableElm = createTable();
|
const tableElm = createTable();
|
||||||
const Overlay = overlayFactory()(tableElm, true);
|
const Overlay = overlayFactory()(true);
|
||||||
wrapper = render(<Overlay />);
|
wrapper = render(<Overlay>{ tableElm }</Overlay>);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering Overlay component correctly', () => {
|
it('should rendering Overlay component correctly', () => {
|
||||||
const overlay = wrapper.find(LoadingOverlay);
|
|
||||||
expect(wrapper.length).toBe(1);
|
expect(wrapper.length).toBe(1);
|
||||||
expect(overlay.length).toBe(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,8 +57,8 @@ describe('overlayFactory', () => {
|
|||||||
};
|
};
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const tableElm = createTable();
|
const tableElm = createTable();
|
||||||
const Overlay = overlayFactory(options)(tableElm, false);
|
const Overlay = overlayFactory(options)(false);
|
||||||
wrapper = shallow(<Overlay />);
|
wrapper = shallow(<Overlay>{ tableElm }</Overlay>);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering Overlay component with options correctly', () => {
|
it('should rendering Overlay component with options correctly', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-paginator",
|
"name": "react-bootstrap-table2-paginator",
|
||||||
"version": "0.1.3",
|
"version": "0.1.6",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ export default {
|
|||||||
PAGE_START_INDEX: 1,
|
PAGE_START_INDEX: 1,
|
||||||
With_FIRST_AND_LAST: true,
|
With_FIRST_AND_LAST: true,
|
||||||
SHOW_ALL_PAGE_BTNS: false,
|
SHOW_ALL_PAGE_BTNS: false,
|
||||||
|
SHOW_TOTAL: false,
|
||||||
|
PAGINATION_TOTAL: null,
|
||||||
FIRST_PAGE_TEXT: '<<',
|
FIRST_PAGE_TEXT: '<<',
|
||||||
PRE_PAGE_TEXT: '<',
|
PRE_PAGE_TEXT: '<',
|
||||||
NEXT_PAGE_TEXT: '>',
|
NEXT_PAGE_TEXT: '>',
|
||||||
|
|||||||
@@ -1,12 +1,39 @@
|
|||||||
|
/* eslint no-param-reassign: 0 */
|
||||||
|
|
||||||
|
const getNormalizedPage = (
|
||||||
|
page,
|
||||||
|
pageStartIndex
|
||||||
|
) => {
|
||||||
|
const offset = Math.abs(1 - pageStartIndex);
|
||||||
|
return page + offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
const endIndex = (
|
||||||
|
page,
|
||||||
|
sizePerPage,
|
||||||
|
pageStartIndex
|
||||||
|
) => (getNormalizedPage(page, pageStartIndex) * sizePerPage) - 1;
|
||||||
|
|
||||||
|
const startIndex = (
|
||||||
|
end,
|
||||||
|
sizePerPage,
|
||||||
|
) => end - (sizePerPage - 1);
|
||||||
|
|
||||||
|
export const alignPage = (store, pageStartIndex, sizePerPage) => {
|
||||||
|
const end = endIndex(store.page, sizePerPage, pageStartIndex);
|
||||||
|
const dataSize = store.data.length;
|
||||||
|
|
||||||
|
if (end - 1 > dataSize) {
|
||||||
|
return pageStartIndex;
|
||||||
|
}
|
||||||
|
return store.page;
|
||||||
|
};
|
||||||
|
|
||||||
export const getByCurrPage = (store, pageStartIndex) => {
|
export const getByCurrPage = (store, pageStartIndex) => {
|
||||||
const dataSize = store.data.length;
|
const dataSize = store.data.length;
|
||||||
if (!dataSize) return [];
|
if (!dataSize) return [];
|
||||||
const getNormalizedPage = () => {
|
const end = endIndex(store.page, store.sizePerPage, pageStartIndex);
|
||||||
const offset = Math.abs(1 - pageStartIndex);
|
const start = startIndex(end, store.sizePerPage);
|
||||||
return store.page + offset;
|
|
||||||
};
|
|
||||||
const end = (getNormalizedPage() * store.sizePerPage) - 1;
|
|
||||||
const start = end - (store.sizePerPage - 1);
|
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
for (let i = start; i <= end; i += 1) {
|
for (let i = start; i <= end; i += 1) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const PaginationTotal = props => (
|
const PaginationTotal = props => (
|
||||||
<span>
|
<span className="react-bootstrap-table-pagination-total">
|
||||||
Showing rows { props.from } to { props.to + 1 } of { props.dataSize }
|
Showing rows { props.from } to { props.to + 1 } of { props.dataSize }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -87,10 +87,28 @@ class Pagination extends pageResolver(Component) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultTotal = (from, to, size) => (
|
||||||
|
<PaginationTotal
|
||||||
|
from={ from }
|
||||||
|
to={ to }
|
||||||
|
dataSize={ size }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
setTotal = (from, to, size, total) => {
|
||||||
|
if (total && (typeof total === 'function')) {
|
||||||
|
return total(from, to, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.defaultTotal(from, to, size);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { totalPages, lastPage, dropdownOpen: open } = this.state;
|
const { totalPages, lastPage, dropdownOpen: open } = this.state;
|
||||||
const {
|
const {
|
||||||
showTotal,
|
showTotal,
|
||||||
|
dataSize,
|
||||||
|
paginationTotalRenderer,
|
||||||
sizePerPageList,
|
sizePerPageList,
|
||||||
currSizePerPage,
|
currSizePerPage,
|
||||||
hideSizePerPage,
|
hideSizePerPage,
|
||||||
@@ -121,11 +139,12 @@ class Pagination extends pageResolver(Component) {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
showTotal ?
|
showTotal ?
|
||||||
<PaginationTotal
|
this.setTotal(
|
||||||
from={ from }
|
from,
|
||||||
to={ to }
|
to,
|
||||||
dataSize={ this.props.dataSize }
|
dataSize,
|
||||||
/> : null
|
paginationTotalRenderer
|
||||||
|
) : null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={ pageListClass }>
|
<div className={ pageListClass }>
|
||||||
@@ -145,6 +164,8 @@ Pagination.propTypes = {
|
|||||||
onSizePerPageChange: PropTypes.func.isRequired,
|
onSizePerPageChange: PropTypes.func.isRequired,
|
||||||
pageStartIndex: PropTypes.number,
|
pageStartIndex: PropTypes.number,
|
||||||
paginationSize: PropTypes.number,
|
paginationSize: PropTypes.number,
|
||||||
|
showTotal: PropTypes.bool,
|
||||||
|
paginationTotalRenderer: PropTypes.func,
|
||||||
firstPageText: PropTypes.string,
|
firstPageText: PropTypes.string,
|
||||||
prePageText: PropTypes.string,
|
prePageText: PropTypes.string,
|
||||||
nextPageText: PropTypes.string,
|
nextPageText: PropTypes.string,
|
||||||
@@ -164,6 +185,8 @@ Pagination.defaultProps = {
|
|||||||
paginationSize: Const.PAGINATION_SIZE,
|
paginationSize: Const.PAGINATION_SIZE,
|
||||||
withFirstAndLast: Const.With_FIRST_AND_LAST,
|
withFirstAndLast: Const.With_FIRST_AND_LAST,
|
||||||
alwaysShowAllBtns: Const.SHOW_ALL_PAGE_BTNS,
|
alwaysShowAllBtns: Const.SHOW_ALL_PAGE_BTNS,
|
||||||
|
showTotal: Const.SHOW_TOTAL,
|
||||||
|
paginationTotalRenderer: Const.PAGINATION_TOTAL,
|
||||||
firstPageText: Const.FIRST_PAGE_TEXT,
|
firstPageText: Const.FIRST_PAGE_TEXT,
|
||||||
prePageText: Const.PRE_PAGE_TEXT,
|
prePageText: Const.PRE_PAGE_TEXT,
|
||||||
nextPageText: Const.NEXT_PAGE_TEXT,
|
nextPageText: Const.NEXT_PAGE_TEXT,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
|||||||
|
|
||||||
import Const from './const';
|
import Const from './const';
|
||||||
import Pagination from './pagination';
|
import Pagination from './pagination';
|
||||||
import { getByCurrPage } from './page';
|
import { getByCurrPage, alignPage } from './page';
|
||||||
|
|
||||||
export default (Base, {
|
export default (Base, {
|
||||||
remoteResolver
|
remoteResolver
|
||||||
@@ -49,16 +49,23 @@ export default (Base, {
|
|||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
let needNewState = false;
|
let needNewState = false;
|
||||||
let { currPage, currSizePerPage } = this.state;
|
let { currPage, currSizePerPage } = this.state;
|
||||||
const { page, sizePerPage, pageStartIndex, onPageChange } = nextProps.pagination.options;
|
const { page, sizePerPage, onPageChange } = nextProps.pagination.options;
|
||||||
|
|
||||||
|
const pageStartIndex = typeof nextProps.pagination.options.pageStartIndex !== 'undefined' ?
|
||||||
|
nextProps.pagination.options.pageStartIndex : Const.PAGE_START_INDEX;
|
||||||
|
|
||||||
if (typeof page !== 'undefined' && currPage !== page) { // user defined page
|
if (typeof page !== 'undefined' && currPage !== page) { // user defined page
|
||||||
currPage = page;
|
currPage = page;
|
||||||
needNewState = true;
|
needNewState = true;
|
||||||
} else if (nextProps.isDataChanged) { // user didn't defined page but data change
|
} else if (nextProps.isDataChanged) {
|
||||||
currPage = typeof pageStartIndex !== 'undefined' ? pageStartIndex : Const.PAGE_START_INDEX;
|
currPage = alignPage(this.props.store, pageStartIndex, currSizePerPage);
|
||||||
needNewState = true;
|
needNewState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof currPage === 'undefined') {
|
||||||
|
currPage = pageStartIndex;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof sizePerPage !== 'undefined') {
|
if (typeof sizePerPage !== 'undefined') {
|
||||||
currSizePerPage = sizePerPage;
|
currSizePerPage = sizePerPage;
|
||||||
needNewState = true;
|
needNewState = true;
|
||||||
@@ -146,6 +153,7 @@ export default (Base, {
|
|||||||
hideSizePerPage={ hideSizePerPage }
|
hideSizePerPage={ hideSizePerPage }
|
||||||
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
|
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
|
||||||
showTotal={ options.showTotal }
|
showTotal={ options.showTotal }
|
||||||
|
paginationTotalRenderer={ options.paginationTotalRenderer }
|
||||||
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
|
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
|
||||||
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
|
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
|
||||||
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
|
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Store from 'react-bootstrap-table-next/src/store';
|
import Store from 'react-bootstrap-table-next/src/store';
|
||||||
import { getByCurrPage } from '../src/page';
|
import { getByCurrPage, alignPage } from '../src/page';
|
||||||
|
|
||||||
describe('Page Functions', () => {
|
describe('Page Functions', () => {
|
||||||
let data;
|
let data;
|
||||||
@@ -48,4 +48,40 @@ describe('Page Functions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('alignPage', () => {
|
||||||
|
const pageStartIndex = 1;
|
||||||
|
const sizePerPage = 10;
|
||||||
|
describe('if the length of store.data is less than the end page index', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
data = [];
|
||||||
|
for (let i = 0; i < 15; i += 1) {
|
||||||
|
data.push({ id: i, name: `test_name${i}` });
|
||||||
|
}
|
||||||
|
store = new Store('id');
|
||||||
|
store.data = data;
|
||||||
|
store.page = 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return pageStartIndex argument', () => {
|
||||||
|
expect(alignPage(store, pageStartIndex, sizePerPage)).toEqual(pageStartIndex);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if the length of store.data is large than the end page index', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
data = [];
|
||||||
|
for (let i = 0; i < 30; i += 1) {
|
||||||
|
data.push({ id: i, name: `test_name${i}` });
|
||||||
|
}
|
||||||
|
store = new Store('id');
|
||||||
|
store.data = data;
|
||||||
|
store.page = 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return current page', () => {
|
||||||
|
expect(alignPage(store, pageStartIndex, sizePerPage)).toEqual(store.page);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const data = [];
|
|||||||
for (let i = 0; i < 100; i += 1) {
|
for (let i = 0; i < 100; i += 1) {
|
||||||
data.push({
|
data.push({
|
||||||
id: i,
|
id: i,
|
||||||
name: `itme name ${i}`
|
name: `item name ${i}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,29 +67,29 @@ describe('Wrapper', () => {
|
|||||||
createPaginationWrapper(props);
|
createPaginationWrapper(props);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering correctly', () => {
|
it('should render correctly', () => {
|
||||||
expect(wrapper.length).toBe(1);
|
expect(wrapper.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should initializing state correctly', () => {
|
it('should initialize state correctly', () => {
|
||||||
expect(instance.state.currPage).toBeDefined();
|
expect(instance.state.currPage).toBeDefined();
|
||||||
expect(instance.state.currPage).toEqual(Const.PAGE_START_INDEX);
|
expect(instance.state.currPage).toEqual(Const.PAGE_START_INDEX);
|
||||||
expect(instance.state.currSizePerPage).toBeDefined();
|
expect(instance.state.currSizePerPage).toBeDefined();
|
||||||
expect(instance.state.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]);
|
expect(instance.state.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should saving page and sizePerPage to store correctly', () => {
|
it('should save page and sizePerPage to the store correctly', () => {
|
||||||
expect(props.store.page).toBe(instance.state.currPage);
|
expect(props.store.page).toBe(instance.state.currPage);
|
||||||
expect(props.store.sizePerPage).toBe(instance.state.currSizePerPage);
|
expect(props.store.sizePerPage).toBe(instance.state.currSizePerPage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering BootstraTable correctly', () => {
|
it('should render BootstrapTable correctly', () => {
|
||||||
const table = wrapper.find(BootstrapTable);
|
const table = wrapper.find(BootstrapTable);
|
||||||
expect(table.length).toBe(1);
|
expect(table.length).toBe(1);
|
||||||
expect(table.prop('data').length).toEqual(instance.state.currSizePerPage);
|
expect(table.prop('data').length).toEqual(instance.state.currSizePerPage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering Pagination correctly', () => {
|
it('should render Pagination correctly', () => {
|
||||||
const pagination = wrapper.find(Pagination);
|
const pagination = wrapper.find(Pagination);
|
||||||
expect(pagination.length).toBe(1);
|
expect(pagination.length).toBe(1);
|
||||||
expect(pagination.prop('dataSize')).toEqual(props.store.data.length);
|
expect(pagination.prop('dataSize')).toEqual(props.store.data.length);
|
||||||
@@ -111,7 +111,7 @@ describe('Wrapper', () => {
|
|||||||
expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE);
|
expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE);
|
||||||
expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE);
|
expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE);
|
||||||
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
|
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
|
||||||
expect(pagination.prop('showTotal')).toEqual(undefined);
|
expect(pagination.prop('showTotal')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('componentWillReceiveProps', () => {
|
describe('componentWillReceiveProps', () => {
|
||||||
@@ -176,22 +176,6 @@ describe('Wrapper', () => {
|
|||||||
expect(props.store.page).toEqual(instance.state.currPage);
|
expect(props.store.page).toEqual(instance.state.currPage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when nextProps.isDataChanged is true and options.pageStartIndex is existing', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
nextProps.isDataChanged = true;
|
|
||||||
nextProps.pagination.options.pageStartIndex = 0;
|
|
||||||
instance.componentWillReceiveProps(nextProps);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should setting currPage state correctly', () => {
|
|
||||||
expect(instance.state.currPage).toBe(nextProps.pagination.options.pageStartIndex);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should saving store.page correctly', () => {
|
|
||||||
expect(props.store.page).toEqual(instance.state.currPage);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -254,7 +238,7 @@ describe('Wrapper', () => {
|
|||||||
createPaginationWrapper(props);
|
createPaginationWrapper(props);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rendering Pagination correctly', () => {
|
it('should render Pagination correctly', () => {
|
||||||
const pagination = wrapper.find(Pagination);
|
const pagination = wrapper.find(Pagination);
|
||||||
expect(wrapper.length).toBe(1);
|
expect(wrapper.length).toBe(1);
|
||||||
expect(pagination.length).toBe(1);
|
expect(pagination.length).toBe(1);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table-next",
|
"name": "react-bootstrap-table-next",
|
||||||
"version": "0.1.12",
|
"version": "0.1.15",
|
||||||
"description": "Next generation of react-bootstrap-table",
|
"description": "Next generation of react-bootstrap-table",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -29,12 +29,15 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loading, overlay } = this.props;
|
const { loading, overlay } = this.props;
|
||||||
const table = this.renderTable();
|
if (overlay) {
|
||||||
if (loading && overlay) {
|
const LoadingOverlay = overlay(loading);
|
||||||
const LoadingOverlay = overlay(table, loading);
|
return (
|
||||||
return <LoadingOverlay />;
|
<LoadingOverlay>
|
||||||
|
{ this.renderTable() }
|
||||||
|
</LoadingOverlay>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return table;
|
return this.renderTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTable() {
|
renderTable() {
|
||||||
@@ -83,10 +86,12 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
{ tableCaption }
|
{ tableCaption }
|
||||||
<Header
|
<Header
|
||||||
columns={ columns }
|
columns={ columns }
|
||||||
|
className={ this.props.headerClasses }
|
||||||
sortField={ store.sortField }
|
sortField={ store.sortField }
|
||||||
sortOrder={ store.sortOrder }
|
sortOrder={ store.sortOrder }
|
||||||
onSort={ this.props.onSort }
|
onSort={ this.props.onSort }
|
||||||
onFilter={ this.props.onFilter }
|
onFilter={ this.props.onFilter }
|
||||||
|
onExternalFilter={ this.props.onExternalFilter }
|
||||||
selectRow={ headerCellSelectionInfo }
|
selectRow={ headerCellSelectionInfo }
|
||||||
/>
|
/>
|
||||||
<Body
|
<Body
|
||||||
@@ -142,13 +147,16 @@ BootstrapTable.propTypes = {
|
|||||||
classes: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
classes: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
nonSelectable: PropTypes.array,
|
nonSelectable: PropTypes.array,
|
||||||
bgColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
bgColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
hideSelectColumn: PropTypes.bool
|
hideSelectColumn: PropTypes.bool,
|
||||||
|
selectionRenderer: PropTypes.func,
|
||||||
|
selectionHeaderRenderer: PropTypes.func
|
||||||
}),
|
}),
|
||||||
onRowSelect: PropTypes.func,
|
onRowSelect: PropTypes.func,
|
||||||
onAllRowsSelect: PropTypes.func,
|
onAllRowsSelect: PropTypes.func,
|
||||||
rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
rowEvents: PropTypes.object,
|
rowEvents: PropTypes.object,
|
||||||
rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
|
headerClasses: PropTypes.string,
|
||||||
defaultSorted: PropTypes.arrayOf(PropTypes.shape({
|
defaultSorted: PropTypes.arrayOf(PropTypes.shape({
|
||||||
dataField: PropTypes.string.isRequired,
|
dataField: PropTypes.string.isRequired,
|
||||||
order: PropTypes.oneOf([Const.SORT_DESC, Const.SORT_ASC]).isRequired
|
order: PropTypes.oneOf([Const.SORT_DESC, Const.SORT_ASC]).isRequired
|
||||||
@@ -157,7 +165,8 @@ BootstrapTable.propTypes = {
|
|||||||
overlay: PropTypes.func,
|
overlay: PropTypes.func,
|
||||||
onTableChange: PropTypes.func,
|
onTableChange: PropTypes.func,
|
||||||
onSort: PropTypes.func,
|
onSort: PropTypes.func,
|
||||||
onFilter: PropTypes.func
|
onFilter: PropTypes.func,
|
||||||
|
onExternalFilter: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
BootstrapTable.defaultProps = {
|
BootstrapTable.defaultProps = {
|
||||||
|
|||||||
@@ -17,13 +17,15 @@ const HeaderCell = (props) => {
|
|||||||
sorting,
|
sorting,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
isLastSorting,
|
isLastSorting,
|
||||||
onFilter
|
onFilter,
|
||||||
|
onExternalFilter
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
text,
|
text,
|
||||||
sort,
|
sort,
|
||||||
filter,
|
filter,
|
||||||
|
filterRenderer,
|
||||||
headerTitle,
|
headerTitle,
|
||||||
headerAlign,
|
headerAlign,
|
||||||
headerFormatter,
|
headerFormatter,
|
||||||
@@ -89,7 +91,11 @@ const HeaderCell = (props) => {
|
|||||||
|
|
||||||
if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses);
|
if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses);
|
||||||
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
|
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
|
||||||
if (filter) {
|
|
||||||
|
if (filterRenderer) {
|
||||||
|
const onCustomFilter = onExternalFilter(column, filter.props.type);
|
||||||
|
filterElm = filterRenderer(onCustomFilter, column);
|
||||||
|
} else if (filter) {
|
||||||
filterElm = <filter.Filter { ...filter.props } onFilter={ onFilter } column={ column } />;
|
filterElm = <filter.Filter { ...filter.props } onFilter={ onFilter } column={ column } />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +142,7 @@ HeaderCell.propTypes = {
|
|||||||
editorRenderer: PropTypes.func,
|
editorRenderer: PropTypes.func,
|
||||||
validator: PropTypes.func,
|
validator: PropTypes.func,
|
||||||
filter: PropTypes.object,
|
filter: PropTypes.object,
|
||||||
|
filterRenderer: PropTypes.func,
|
||||||
filterValue: PropTypes.func
|
filterValue: PropTypes.func
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
index: PropTypes.number.isRequired,
|
index: PropTypes.number.isRequired,
|
||||||
@@ -143,7 +150,8 @@ HeaderCell.propTypes = {
|
|||||||
sorting: PropTypes.bool,
|
sorting: PropTypes.bool,
|
||||||
sortOrder: PropTypes.oneOf([Const.SORT_ASC, Const.SORT_DESC]),
|
sortOrder: PropTypes.oneOf([Const.SORT_ASC, Const.SORT_DESC]),
|
||||||
isLastSorting: PropTypes.bool,
|
isLastSorting: PropTypes.bool,
|
||||||
onFilter: PropTypes.func
|
onFilter: PropTypes.func,
|
||||||
|
onExternalFilter: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
export default HeaderCell;
|
export default HeaderCell;
|
||||||
|
|||||||
11
packages/react-bootstrap-table2/src/header.js
vendored
11
packages/react-bootstrap-table2/src/header.js
vendored
@@ -10,17 +10,19 @@ const Header = (props) => {
|
|||||||
const { ROW_SELECT_DISABLED } = Const;
|
const { ROW_SELECT_DISABLED } = Const;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
className,
|
||||||
columns,
|
columns,
|
||||||
onSort,
|
onSort,
|
||||||
onFilter,
|
onFilter,
|
||||||
sortField,
|
sortField,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
selectRow
|
selectRow,
|
||||||
|
onExternalFilter
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr className={ className }>
|
||||||
{
|
{
|
||||||
(selectRow.mode !== ROW_SELECT_DISABLED && !selectRow.hideSelectColumn)
|
(selectRow.mode !== ROW_SELECT_DISABLED && !selectRow.hideSelectColumn)
|
||||||
? <SelectionHeaderCell { ...selectRow } /> : null
|
? <SelectionHeaderCell { ...selectRow } /> : null
|
||||||
@@ -39,6 +41,7 @@ const Header = (props) => {
|
|||||||
onSort={ onSort }
|
onSort={ onSort }
|
||||||
sorting={ currSort }
|
sorting={ currSort }
|
||||||
onFilter={ onFilter }
|
onFilter={ onFilter }
|
||||||
|
onExternalFilter={ onExternalFilter }
|
||||||
sortOrder={ sortOrder }
|
sortOrder={ sortOrder }
|
||||||
isLastSorting={ isLastSorting }
|
isLastSorting={ isLastSorting }
|
||||||
/>);
|
/>);
|
||||||
@@ -57,7 +60,9 @@ Header.propTypes = {
|
|||||||
onFilter: PropTypes.func,
|
onFilter: PropTypes.func,
|
||||||
sortField: PropTypes.string,
|
sortField: PropTypes.string,
|
||||||
sortOrder: PropTypes.string,
|
sortOrder: PropTypes.string,
|
||||||
selectRow: PropTypes.object
|
selectRow: PropTypes.object,
|
||||||
|
onExternalFilter: PropTypes.func,
|
||||||
|
className: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ export default class SelectionCell extends Component {
|
|||||||
onRowSelect: PropTypes.func,
|
onRowSelect: PropTypes.func,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
rowIndex: PropTypes.number,
|
rowIndex: PropTypes.number,
|
||||||
clickToSelect: PropTypes.bool
|
clickToSelect: PropTypes.bool,
|
||||||
|
selectionRenderer: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -53,16 +54,25 @@ export default class SelectionCell extends Component {
|
|||||||
const {
|
const {
|
||||||
mode: inputType,
|
mode: inputType,
|
||||||
selected,
|
selected,
|
||||||
disabled
|
disabled,
|
||||||
|
selectionRenderer
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<td onClick={ this.handleClick }>
|
<td onClick={ this.handleClick }>
|
||||||
<input
|
{
|
||||||
type={ inputType }
|
selectionRenderer ? selectionRenderer({
|
||||||
checked={ selected }
|
mode: inputType,
|
||||||
disabled={ disabled }
|
checked: selected,
|
||||||
/>
|
disabled
|
||||||
|
}) : (
|
||||||
|
<input
|
||||||
|
type={ inputType }
|
||||||
|
checked={ selected }
|
||||||
|
disabled={ disabled }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export default class SelectionHeaderCell extends Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
mode: PropTypes.string.isRequired,
|
mode: PropTypes.string.isRequired,
|
||||||
checkedStatus: PropTypes.string,
|
checkedStatus: PropTypes.string,
|
||||||
onAllRowsSelect: PropTypes.func
|
onAllRowsSelect: PropTypes.func,
|
||||||
|
selectionHeaderRenderer: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -52,25 +53,37 @@ export default class SelectionHeaderCell extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_SINGLE
|
CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_MULTIPLE
|
||||||
} = Const;
|
} = Const;
|
||||||
|
|
||||||
const { mode, checkedStatus } = this.props;
|
const { mode, checkedStatus, selectionHeaderRenderer } = this.props;
|
||||||
|
|
||||||
const checked = checkedStatus === CHECKBOX_STATUS_CHECKED;
|
const checked = checkedStatus === CHECKBOX_STATUS_CHECKED;
|
||||||
|
|
||||||
const indeterminate = checkedStatus === CHECKBOX_STATUS_INDETERMINATE;
|
const indeterminate = checkedStatus === CHECKBOX_STATUS_INDETERMINATE;
|
||||||
|
|
||||||
return mode === ROW_SELECT_SINGLE
|
const attrs = {};
|
||||||
? <th data-row-selection />
|
let content;
|
||||||
: (
|
if (selectionHeaderRenderer) {
|
||||||
<th data-row-selection onClick={ this.handleCheckBoxClick }>
|
content = selectionHeaderRenderer({
|
||||||
<CheckBox
|
mode,
|
||||||
{ ...this.props }
|
checked,
|
||||||
checked={ checked }
|
indeterminate
|
||||||
indeterminate={ indeterminate }
|
});
|
||||||
/>
|
attrs.onClick = this.handleCheckBoxClick;
|
||||||
</th>
|
} else if (mode === ROW_SELECT_MULTIPLE) {
|
||||||
|
content = (
|
||||||
|
<CheckBox
|
||||||
|
{ ...this.props }
|
||||||
|
checked={ checked }
|
||||||
|
indeterminate={ indeterminate }
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
attrs.onClick = this.handleCheckBoxClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<th data-row-selection { ...attrs }>{ content }</th>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,15 +39,17 @@ export default Base =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
let sortedColumn;
|
if (!this.isRemoteSort() && !this.isRemotePagination()) {
|
||||||
for (let i = 0; i < nextProps.columns.length; i += 1) {
|
let sortedColumn;
|
||||||
if (nextProps.columns[i].dataField === nextProps.store.sortField) {
|
for (let i = 0; i < nextProps.columns.length; i += 1) {
|
||||||
sortedColumn = nextProps.columns[i];
|
if (nextProps.columns[i].dataField === nextProps.store.sortField) {
|
||||||
break;
|
sortedColumn = nextProps.columns[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortedColumn && sortedColumn.sort) {
|
||||||
|
nextProps.store.sortBy(sortedColumn);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (sortedColumn && sortedColumn.sort) {
|
|
||||||
nextProps.store.sortBy(sortedColumn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -669,4 +669,74 @@ describe('HeaderCell', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when column.filter is defined', () => {
|
||||||
|
const onFilter = jest.fn();
|
||||||
|
const filterProps = { a: 123 };
|
||||||
|
const Filter = () => <div>test</div>;
|
||||||
|
let column;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
onFilter.mockClear();
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
filter: {
|
||||||
|
props: filterProps,
|
||||||
|
Filter
|
||||||
|
}
|
||||||
|
};
|
||||||
|
wrapper = shallow(<HeaderCell column={ column } index={ index } onFilter={ onFilter } />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render successfully', () => {
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(wrapper.find('th').length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render filter correctly', () => {
|
||||||
|
expect(wrapper.find(Filter).length).toBe(1);
|
||||||
|
expect(wrapper.find(Filter).props()).toEqual({
|
||||||
|
column,
|
||||||
|
onFilter,
|
||||||
|
...filterProps
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when column.filter and column.filterRenderer is defined', () => {
|
||||||
|
const onExternalFilter = jest.fn();
|
||||||
|
const filterProps = { a: 123 };
|
||||||
|
const Filter = () => <div>test</div>;
|
||||||
|
const filterRenderer = jest.fn().mockReturnValue(<Filter />);
|
||||||
|
let column;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
onExternalFilter.mockClear();
|
||||||
|
filterRenderer.mockClear();
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
filter: {
|
||||||
|
props: filterProps
|
||||||
|
},
|
||||||
|
filterRenderer
|
||||||
|
};
|
||||||
|
wrapper = shallow(
|
||||||
|
<HeaderCell column={ column } index={ index } onExternalFilter={ onExternalFilter } />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render successfully', () => {
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(wrapper.find('th').length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render filter correctly', () => {
|
||||||
|
expect(wrapper.find(Filter).length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call filterRenderer function correctly', () => {
|
||||||
|
expect(filterRenderer).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,6 +29,25 @@ describe('Header', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('className prop is exists', () => {
|
||||||
|
const className = 'test-class';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = shallow(
|
||||||
|
<Header
|
||||||
|
{ ...mockHeaderResolvedProps }
|
||||||
|
columns={ columns }
|
||||||
|
className={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render successfully', () => {
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(wrapper.find(`.${className}`).length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('header with columns enable sort', () => {
|
describe('header with columns enable sort', () => {
|
||||||
const sortField = columns[1].dataField;
|
const sortField = columns[1].dataField;
|
||||||
|
|
||||||
|
|||||||
@@ -193,5 +193,36 @@ describe('<SelectionCell />', () => {
|
|||||||
expect(wrapper.find('input').get(0).props.disabled).toBeTruthy();
|
expect(wrapper.find('input').get(0).props.disabled).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when selectionRenderer prop is defined', () => {
|
||||||
|
const DummySelection = () => <div className="dummy" />;
|
||||||
|
const selectionRenderer = jest.fn().mockReturnValue(<DummySelection />);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
selectionRenderer.mockClear();
|
||||||
|
wrapper = shallow(
|
||||||
|
<SelectionCell
|
||||||
|
rowKey={ 1 }
|
||||||
|
mode={ mode }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
selected={ selected }
|
||||||
|
selectionRenderer={ selectionRenderer }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render component correctly', () => {
|
||||||
|
expect(wrapper.find(DummySelection)).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call props.selectionRenderer correctly', () => {
|
||||||
|
expect(selectionRenderer).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionRenderer).toHaveBeenCalledWith({
|
||||||
|
mode,
|
||||||
|
checked: selected,
|
||||||
|
disabled: wrapper.prop('disabled')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -126,6 +126,36 @@ describe('<SelectionHeaderCell />', () => {
|
|||||||
expect(wrapper.find(CheckBox).get(0).props.indeterminate).toBe(indeterminate);
|
expect(wrapper.find(CheckBox).get(0).props.indeterminate).toBe(indeterminate);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when props.selectionHeaderRenderer is defined', () => {
|
||||||
|
const checkedStatus = Const.CHECKBOX_STATUS_CHECKED;
|
||||||
|
const DummySelection = () => <div className="dummy" />;
|
||||||
|
const selectionHeaderRenderer = jest.fn().mockReturnValue(<DummySelection />);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
selectionHeaderRenderer.mockClear();
|
||||||
|
wrapper = shallow(
|
||||||
|
<SelectionHeaderCell
|
||||||
|
mode="checkbox"
|
||||||
|
checkedStatus={ checkedStatus }
|
||||||
|
selectionHeaderRenderer={ selectionHeaderRenderer }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render correctly', () => {
|
||||||
|
expect(wrapper.find(DummySelection)).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call props.selectionHeaderRenderer correctly', () => {
|
||||||
|
expect(selectionHeaderRenderer).toHaveBeenCalledTimes(1);
|
||||||
|
expect(selectionHeaderRenderer).toHaveBeenCalledWith({
|
||||||
|
mode: 'checkbox',
|
||||||
|
checked: checkedStatus === Const.CHECKBOX_STATUS_CHECKED,
|
||||||
|
indeterminate: checkedStatus === Const.CHECKBOX_STATUS_INDETERMINATE
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user