mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2026-06-29 13:40:07 +00:00
Compare commits
150 Commits
react-boot
...
react-boot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
765a49fb07 | ||
|
|
fe2fd93c20 | ||
|
|
19ba336e32 | ||
|
|
a50148fe85 | ||
|
|
c96156503f | ||
|
|
ed2ba2a5c5 | ||
|
|
f87fe3e544 | ||
|
|
43e73313e6 | ||
|
|
888aa1d08b | ||
|
|
028834da8b | ||
|
|
8f3b989b00 | ||
|
|
fe8761427d | ||
|
|
27a09de008 | ||
|
|
20ba8cc24e | ||
|
|
b8b52e7fc0 | ||
|
|
05a8c3be5f | ||
|
|
2f9bedbeeb | ||
|
|
01be6fc275 | ||
|
|
c20a4bb220 | ||
|
|
ed21b3cb65 | ||
|
|
f2a44c976d | ||
|
|
ca5189d8ad | ||
|
|
03f51c36ac | ||
|
|
607202b4e9 | ||
|
|
4db4f4fb2d | ||
|
|
1d7df6819e | ||
|
|
e4b6993692 | ||
|
|
b15d7a3412 | ||
|
|
b172c6801c | ||
|
|
dc1f4dcc38 | ||
|
|
a82e611358 | ||
|
|
c64951fd6f | ||
|
|
a35701fabf | ||
|
|
f54c1f77b4 | ||
|
|
377534512a | ||
|
|
09032349d0 | ||
|
|
4dd39aeed8 | ||
|
|
a1477e2ad3 | ||
|
|
f34cb4bf63 | ||
|
|
3dc9cd3941 | ||
|
|
e8458b4b63 | ||
|
|
1d87ce9ffc | ||
|
|
88e1a0774b | ||
|
|
11d4f40089 | ||
|
|
41dc3ef619 | ||
|
|
4501ddb632 | ||
|
|
05657ee217 | ||
|
|
c91f521913 | ||
|
|
9ee9c7de43 | ||
|
|
42dbd00fd9 | ||
|
|
bd9150f88f | ||
|
|
3956fbca11 | ||
|
|
240bcd75c0 | ||
|
|
6de57737ea | ||
|
|
33a8da701b | ||
|
|
d5ddd8c3af | ||
|
|
6f9361934a | ||
|
|
6bc81dddd0 | ||
|
|
c11539b9fb | ||
|
|
94f1a5ee57 | ||
|
|
de27072ceb | ||
|
|
55336108a0 | ||
|
|
923439dc81 | ||
|
|
d80ae13513 | ||
|
|
ceebdf5a13 | ||
|
|
0eda54b772 | ||
|
|
3ed4d87b29 | ||
|
|
8a8c2d4964 | ||
|
|
3cea9658c7 | ||
|
|
9f9203bffa | ||
|
|
4011cae18e | ||
|
|
60f32f0336 | ||
|
|
a5cb806d98 | ||
|
|
9382ed587b | ||
|
|
a11913c49a | ||
|
|
4635b60da0 | ||
|
|
4d9e20e9c8 | ||
|
|
931cf80450 | ||
|
|
5dd1f1e9ea | ||
|
|
a8083ac17d | ||
|
|
096799c403 | ||
|
|
6dee718081 | ||
|
|
936a82954c | ||
|
|
ba24990994 | ||
|
|
e7ccd47817 | ||
|
|
a0af964d76 | ||
|
|
865be93ef7 | ||
|
|
65a596a0e9 | ||
|
|
024bba15fa | ||
|
|
f9217930e7 | ||
|
|
fc34ea12e6 | ||
|
|
b0f411e934 | ||
|
|
28a1077bad | ||
|
|
ca32eee28e | ||
|
|
7030b54cbd | ||
|
|
4d7378e3f1 | ||
|
|
88234fead0 | ||
|
|
dea780519f | ||
|
|
577973a147 | ||
|
|
c4f14e2b69 | ||
|
|
38bb2290dc | ||
|
|
feedcb9f4b | ||
|
|
8bfbc14bd9 | ||
|
|
ee4eb8f2c6 | ||
|
|
8fa6389c81 | ||
|
|
9a354444d0 | ||
|
|
2533a63430 | ||
|
|
81e0080aa6 | ||
|
|
094a0682f1 | ||
|
|
3f2c6201d9 | ||
|
|
280c423298 | ||
|
|
fc813e80b6 | ||
|
|
4bb2ae2ba0 |
@@ -9,9 +9,10 @@ cache:
|
|||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
# skip master branch when it's under development phase
|
- master
|
||||||
# - master
|
|
||||||
- develop
|
- develop
|
||||||
|
except:
|
||||||
|
- gh-pages-src
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s
|
- curl -o- -L https://yarnpkg.com/install.sh | bash -s
|
||||||
|
|||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 react-bootstrap-table2
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
# react-bootstrap-table2
|
# react-bootstrap-table2
|
||||||
|
[](https://travis-ci.org/react-bootstrap-table/react-bootstrap-table2)
|
||||||
Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table)
|
Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table)
|
||||||
|
|
||||||
> `react-bootstrap-table2`'s npm module name is [**`react-bootstrap-table-next`**](https://www.npmjs.com/package/react-bootstrap-table-next) due to some guys already used it
|
> `react-bootstrap-table2`'s npm module name is [**`react-bootstrap-table-next`**](https://www.npmjs.com/package/react-bootstrap-table-next) due to some guys already used it
|
||||||
|
|||||||
@@ -15,12 +15,16 @@
|
|||||||
* [bordered](#bordered)
|
* [bordered](#bordered)
|
||||||
* [hover](#hover)
|
* [hover](#hover)
|
||||||
* [condensed](#condensed)
|
* [condensed](#condensed)
|
||||||
|
* [id](#id)
|
||||||
|
* [classes](#classes)
|
||||||
|
* [wrapperClasses](#wrapperClasses)
|
||||||
* [cellEdit](#cellEdit)
|
* [cellEdit](#cellEdit)
|
||||||
* [selectRow](#selectRow)
|
* [selectRow](#selectRow)
|
||||||
* [rowStyle](#rowStyle)
|
* [rowStyle](#rowStyle)
|
||||||
* [rowClasses](#rowClasses)
|
* [rowClasses](#rowClasses)
|
||||||
* [rowEvents](#rowEvents)
|
* [rowEvents](#rowEvents)
|
||||||
* [defaultSorted](#defaultSorted)
|
* [defaultSorted](#defaultSorted)
|
||||||
|
* [defaultSortDirection](#defaultSortDirection)
|
||||||
* [pagination](#pagination)
|
* [pagination](#pagination)
|
||||||
* [filter](#filter)
|
* [filter](#filter)
|
||||||
* [onTableChange](#onTableChange)
|
* [onTableChange](#onTableChange)
|
||||||
@@ -59,14 +63,14 @@ A special case for remote pagination:
|
|||||||
remote={ { pagination: true, filter: false, sort: false } }
|
remote={ { pagination: true, filter: false, sort: false } }
|
||||||
```
|
```
|
||||||
|
|
||||||
There is a apecial case for remote pagination, even you only specified the paignation need to handle as remote, `react-bootstrap-table2` will handle all the table changes(filter, sort etc) as remote mode, because `react-bootstrap-table2` only know the data of current page, but filtering, searching or sort need to work on overall datas.
|
There is a special case for remote pagination, even you only specified the pagination need to handle as remote, `react-bootstrap-table2` will handle all the table changes(filter, sort etc) as remote mode, because `react-bootstrap-table2` only know the data of current page, but filtering, searching or sort need to work on overall data.
|
||||||
|
|
||||||
### <a name='loading'>loading - [Bool]</a>
|
### <a name='loading'>loading - [Bool]</a>
|
||||||
Telling if table is loading or not, for example: waiting data loading, filtering etc. It's **only** valid when [`remote`](#remote) is enabled.
|
Telling if table is loading or not, for example: waiting data loading, filtering etc. It's **only** valid when [`remote`](#remote) is enabled.
|
||||||
When `loading` is `true`, `react-bootstrap-table2` will attend to render a overlay on table via [`overlay`](#overlay) prop, if [`overlay`](#overlay) prop is not given, `react-bootstrap-table2` will ignore the overlay rendering.
|
When `loading` is `true`, `react-bootstrap-table2` will attend to render a overlay on table via [`overlay`](#overlay) prop, if [`overlay`](#overlay) prop is not given, `react-bootstrap-table2` will ignore the overlay rendering.
|
||||||
|
|
||||||
### <a name='overlay'>overlay - [Function]</a>
|
### <a name='overlay'>overlay - [Function]</a>
|
||||||
`overlay` accept a factory funtion which should returning a higher order component. By default, `react-bootstrap-table2-overlay` can be a good option for you:
|
`overlay` accept a factory function which should returning a higher order component. By default, `react-bootstrap-table2-overlay` can be a good option for you:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ npm install react-bootstrap-table2-overlay
|
$ npm install react-bootstrap-table2-overlay
|
||||||
@@ -100,6 +104,13 @@ Same as bootstrap `.table-hover` class for adding mouse hover effect (grey backg
|
|||||||
### <a name='condensed'>condensed - [Bool]</a>
|
### <a name='condensed'>condensed - [Bool]</a>
|
||||||
Same as bootstrap `.table-condensed` class for making a table more compact by cutting cell padding in half.
|
Same as bootstrap `.table-condensed` class for making a table more compact by cutting cell padding in half.
|
||||||
|
|
||||||
|
### <a name='id'>id - [String]</a>
|
||||||
|
Customize id on `table` element.
|
||||||
|
### <a name='classes'>classes - [String]</a>
|
||||||
|
Customize class on `table` element.
|
||||||
|
|
||||||
|
### <a name='wrapperClasses'>wrapperClasses - [String]</a>
|
||||||
|
Customize class on the outer element which wrap up the `table` element.
|
||||||
### <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.
|
||||||
|
|
||||||
@@ -145,7 +156,7 @@ Custom the events on row:
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const rowEvents = {
|
const rowEvents = {
|
||||||
onClick: (e) => {
|
onClick: (e, row, rowIndex) => {
|
||||||
....
|
....
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -162,8 +173,11 @@ const defaultSorted = [{
|
|||||||
}];
|
}];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <a name='defaultSortDirection'>defaultSortDirection - [String]</a>
|
||||||
|
Default sort direction when user click on header column at first time, available value is `asc` and `desc`. Default is `desc`.
|
||||||
|
|
||||||
### <a name='pagination'>pagination - [Object]</a>
|
### <a name='pagination'>pagination - [Object]</a>
|
||||||
`pagination` allow user to render a pagination panel on the bottom of table. But pagination funcitonality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-paginator` additionaly.
|
`pagination` allow user to render a pagination panel on the bottom of table. But pagination functionality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-paginator` additionally.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ npm install react-bootstrap-table2-paginator --save
|
$ npm install react-bootstrap-table2-paginator --save
|
||||||
@@ -188,6 +202,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
|
||||||
}, {
|
}, {
|
||||||
@@ -205,15 +220,16 @@ paginator({
|
|||||||
prePageTitle: 'Go to previous', // the title of previous page button
|
prePageTitle: 'Go to previous', // the title of previous page button
|
||||||
firstPageTitle: 'Go to first', // the title of first page button
|
firstPageTitle: 'Go to first', // the title of first page button
|
||||||
lastPageTitle: 'Go to last', // the title of last page button
|
lastPageTitle: 'Go to last', // the title of last page button
|
||||||
hideSizePerPage: true, // hide the size per page dorpdown
|
hideSizePerPage: true, // hide the size per page dropdown
|
||||||
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
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### <a name='filter'>filter - [Object]</a>
|
### <a name='filter'>filter - [Object]</a>
|
||||||
`filter` allow user to filter data by column. However, filter funcitonality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-filter` firstly.
|
`filter` allow user to filter data by column. However, filter functionality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-filter` firstly.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ npm install react-bootstrap-table2-filter --save
|
$ npm install react-bootstrap-table2-filter --save
|
||||||
|
|||||||
130
docs/columns.md
130
docs/columns.md
@@ -12,6 +12,7 @@ Available properties in a column object:
|
|||||||
* [formatExtraData](#formatExtraData)
|
* [formatExtraData](#formatExtraData)
|
||||||
* [sort](#sort)
|
* [sort](#sort)
|
||||||
* [sortFunc](#sortFunc)
|
* [sortFunc](#sortFunc)
|
||||||
|
* [onSort](#onSort)
|
||||||
* [classes](#classes)
|
* [classes](#classes)
|
||||||
* [style](#style)
|
* [style](#style)
|
||||||
* [title](#title)
|
* [title](#title)
|
||||||
@@ -31,6 +32,10 @@ Available properties in a column object:
|
|||||||
* [validator](#validator)
|
* [validator](#validator)
|
||||||
* [editCellStyle](#editCellStyle)
|
* [editCellStyle](#editCellStyle)
|
||||||
* [editCellClasses](#editCellClasses)
|
* [editCellClasses](#editCellClasses)
|
||||||
|
* [editorStyle](#editorStyle)
|
||||||
|
* [editorClasses](#editorClasses)
|
||||||
|
* [editor](#editor)
|
||||||
|
* [editorRenderer](#editorRenderer)
|
||||||
* [filter](#filter)
|
* [filter](#filter)
|
||||||
* [filterValue](#filterValue)
|
* [filterValue](#filterValue)
|
||||||
|
|
||||||
@@ -122,8 +127,21 @@ Enable the column sort via a `true` value given.
|
|||||||
```
|
```
|
||||||
> The possible value of `order` argument is **`asc`** and **`desc`**.
|
> The possible value of `order` argument is **`asc`** and **`desc`**.
|
||||||
|
|
||||||
|
## <a name='sortFunc'>column.onSort - [Function]</a>
|
||||||
|
`column.onSort` is an event listener for sort change event:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
// omit...
|
||||||
|
sort: true,
|
||||||
|
onSort: (field, order) => {
|
||||||
|
// ....
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## <a name='classes'>column.classes - [String | Function]</a>
|
## <a name='classes'>column.classes - [String | Function]</a>
|
||||||
It's availabe to have custom class on table column:
|
It's available to have custom class on table column:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
@@ -151,7 +169,7 @@ In addition, `classes` also accept a callback function which have more power to
|
|||||||
A new `String` will be the result as element class.
|
A new `String` will be the result as element class.
|
||||||
|
|
||||||
## <a name='headerClasses'>column.headerClasses - [String | Function]</a>
|
## <a name='headerClasses'>column.headerClasses - [String | Function]</a>
|
||||||
It's similar to [`column.classes`](#classes), `headerClasses` is availabe to have customized class on table header column:
|
It's similar to [`column.classes`](#classes), `headerClasses` is available to have customized class on table header column:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
@@ -176,7 +194,7 @@ Furthermore, it also accept a callback function which takes 2 arguments and a `S
|
|||||||
A new `String` will be the result of element headerClasses.
|
A new `String` will be the result of element headerClasses.
|
||||||
|
|
||||||
## <a name='style'>column.style - [Object | Function]</a>
|
## <a name='style'>column.style - [Object | Function]</a>
|
||||||
It's availabe to have custom style on table column:
|
It's available to have custom style on table column:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
@@ -206,7 +224,7 @@ A new `Object` will be the result of element style.
|
|||||||
|
|
||||||
|
|
||||||
## <a name='headerStyle'>column.headerStyle - [Object | Function]</a>
|
## <a name='headerStyle'>column.headerStyle - [Object | Function]</a>
|
||||||
It's availabe to have customized inline-style on table header column:
|
It's available to have customized inline-style on table header column:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
@@ -264,7 +282,7 @@ A new `String` will be the result of element title.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
It's also availabe to custom via a callback function:
|
It's also available to custom via a callback function:
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
headerTitle: function callback(column, colIndex) { ... }
|
headerTitle: function callback(column, colIndex) { ... }
|
||||||
@@ -387,7 +405,7 @@ A new `Object` will be the result of element HTML attributes.
|
|||||||
|
|
||||||
> Caution:
|
> Caution:
|
||||||
|
|
||||||
> If `column.classes`, `column.style`, `column.title`, `column.hidden` or `column.align` was given at the same time, property `attrs` has lower priorty and it will be overwrited.
|
> If `column.classes`, `column.style`, `column.title`, `column.hidden` or `column.align` was given at the same time, property `attrs` has lower priority and it will be overwritten.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
@@ -398,7 +416,7 @@ A new `Object` will be the result of element HTML attributes.
|
|||||||
```
|
```
|
||||||
|
|
||||||
## <a name='headerAttrs'>column.headerAttrs - [Object | Function]</a>
|
## <a name='headerAttrs'>column.headerAttrs - [Object | Function]</a>
|
||||||
`headerAttrs` is similiar to [`column.attrs`](#attrs) but it works for header column.
|
`headerAttrs` is similar to [`column.attrs`](#attrs) but it works for header column.
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
// omit...
|
// omit...
|
||||||
@@ -430,7 +448,7 @@ A new `Object` will be the result of element headerAttrs.
|
|||||||
|
|
||||||
> Caution:
|
> Caution:
|
||||||
> Same as [column.attrs](#attrs), it has lower priority and will be
|
> Same as [column.attrs](#attrs), it has lower priority and will be
|
||||||
> overwrited when other props related to HTML attributes were given.
|
> overwritten when other props related to HTML attributes were given.
|
||||||
|
|
||||||
### <a name='headerSortingClasses'>headerSortingClasses - [String | Function]</a>
|
### <a name='headerSortingClasses'>headerSortingClasses - [String | Function]</a>
|
||||||
|
|
||||||
@@ -453,7 +471,7 @@ const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => { .
|
|||||||
|
|
||||||
### <a name='headerSortingStyle'>headerSortingStyle - [Object | Function]</a>
|
### <a name='headerSortingStyle'>headerSortingStyle - [Object | Function]</a>
|
||||||
|
|
||||||
It's similiar to [headerSortingClasses](#headerSortingClasses). It allows to customize the style of header cell when this column is sorting. A style `Object` and `callback` are acceptable. `callback` takes **4** arguments and an `Object` is expected to return:
|
It's similar to [headerSortingClasses](#headerSortingClasses). It allows to customize the style of header cell when this column is sorting. A style `Object` and `callback` are acceptable. `callback` takes **4** arguments and an `Object` is expected to return:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const sortingHeaderStyle = {
|
const sortingHeaderStyle = {
|
||||||
@@ -488,7 +506,7 @@ If a callback function given, you can control the editable level as cell level:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The return value can be a bool or an object. If your valiation is pass, return `true` explicitly. If your valiation is invalid, return following object instead:
|
The return value can be a bool or an object. If your validation is pass, return `true` explicitly. If your validation is invalid, return following object instead:
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
valid: false,
|
valid: false,
|
||||||
@@ -538,10 +556,100 @@ Or take a callback function
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## <a name='editorStyle'>column.editorStyle - [Object | Function]</a>
|
||||||
|
This is almost same as [`column.editCellStyle`](#editCellStyle), but `column.editorStyle` is custom the style on editor instead of cell(`td`).
|
||||||
|
|
||||||
|
## <a name='editorClasses'>column.editorClasses - [Object | Function]</a>
|
||||||
|
This is almost same as [`column.editCellClasses`](#editCellClasses), but `column.editorClasses` is custom the class on editor instead of cell(`td`).
|
||||||
|
|
||||||
|
## <a name='editor'>column.editor - [Object]</a>
|
||||||
|
`column.editor` allow you to custom the type of cell editor by following predefined type:
|
||||||
|
|
||||||
|
* Text(Default)
|
||||||
|
* Dropdown
|
||||||
|
* Date
|
||||||
|
* Textarea
|
||||||
|
* Checkbox
|
||||||
|
|
||||||
|
Following is a quite example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
//...
|
||||||
|
, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want more information, please check [here](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-editor).
|
||||||
|
|
||||||
|
## <a name='editorRenderer'>column.editorRenderer - [Function]</a>
|
||||||
|
If you feel above predefined editors are not satisfied to your requirement, you can totally custom the editor via `column.editorRenderer`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
// Custom Editor
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
//...
|
||||||
|
, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) =>
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
## <a name='filter'>column.filter - [Object]</a>
|
## <a name='filter'>column.filter - [Object]</a>
|
||||||
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
|
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
|
||||||
|
|
||||||
* Text(`textFilter`)
|
* Text(`textFilter`)
|
||||||
|
* 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`:
|
||||||
|
|
||||||
@@ -559,7 +667,7 @@ import { textFilter } from 'react-bootstrap-table2-filter';
|
|||||||
For some reason of simple customization, `react-bootstrap-table2` allow you to pass some props to filter factory function. Please check [here](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-filter/README.md) for more detail tutorial.
|
For some reason of simple customization, `react-bootstrap-table2` allow you to pass some props to filter factory function. Please check [here](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-filter/README.md) for more detail tutorial.
|
||||||
|
|
||||||
## <a name='filterValue'>column.filterValue - [Function]</a>
|
## <a name='filterValue'>column.filterValue - [Function]</a>
|
||||||
Sometimes, if the cell/column value that you don't want to filter on them, you can define `filterValue` to return a actual value you wanna be filterd:
|
Sometimes, if the cell/column value that you don't want to filter on them, you can define `filterValue` to return a actual value you wanna be filtered:
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
* `cell`: The value of current cell.
|
* `cell`: The value of current cell.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Migration Guide
|
# Migration Guide
|
||||||
|
|
||||||
* Please see the [CHANGELOG](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/new-version-0.1.0.html) for `react-bootstrap-table2` first drop.
|
* Please see the [CHANGELOG](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/new-version-0.1.0.html) for `react-bootstrap-table2` first drop.
|
||||||
* Please see the [Roadmap](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html) for `react-bootstrap-table2` in 2018/Q1.
|
* Please see the [Road Map](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html) for `react-bootstrap-table2` in 2018/Q1.
|
||||||
* Feel free to see the [offical docs](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/about.html), we list all the basic usage here!!
|
* Feel free to see the [official docs](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/about.html), we list all the basic usage here!!
|
||||||
|
|
||||||
## Preface
|
## Preface
|
||||||
|
|
||||||
@@ -23,11 +23,11 @@ Currently, **I still can't implement all the mainly features in legacy `react-bo
|
|||||||
* [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
|
* [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
|
||||||
* Overlay/Loading Addons
|
* Overlay/Loading Addons
|
||||||
|
|
||||||
This can help your application with less bundled size and also help `react-bootstrap-table2` have clean design to avoid handling to much logic in kernal module(SRP). Hence, which means you probably need to install above addons when you need specific features.
|
This can help your application with less bundled size and also help `react-bootstrap-table2` have clean design to avoid handling to much logic in kernel module(SRP). Hence, which means you probably need to install above addons when you need specific features.
|
||||||
|
|
||||||
## Core Table Migration
|
## Core Table Migration
|
||||||
|
|
||||||
There is a big chagne is that there's no `TableHeaderColumn` in the `react-bootstrap-table2`, instead you are supposed to be define the `columns` prop on `BootstrapTable`:
|
There is a big change is that there's no `TableHeaderColumn` in the `react-bootstrap-table2`, instead you are supposed to be define the `columns` prop on `BootstrapTable`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import BootstrapTable from 'react-bootstrap-table-next';
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
@@ -48,8 +48,8 @@ const columns = [{
|
|||||||
|
|
||||||
The `text` property is just same as the children for the `TableHeaderColumn`, if you want to custom the header, there's a new property is: [`headerFormatter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnheaderformatter-function).
|
The `text` property is just same as the children for the `TableHeaderColumn`, if you want to custom the header, there's a new property is: [`headerFormatter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnheaderformatter-function).
|
||||||
|
|
||||||
* [`BootstrapTable` Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html)
|
* [`BootstrapTable` Definition](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html)
|
||||||
* [Column Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html)
|
* [Column Definition](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html)
|
||||||
|
|
||||||
## Table Sort
|
## Table Sort
|
||||||
|
|
||||||
@@ -60,18 +60,19 @@ Please see [Work with table sort](https://react-bootstrap-table.github.io/react-
|
|||||||
- [x] Default Sort
|
- [x] Default Sort
|
||||||
- [x] Remote mode
|
- [x] Remote mode
|
||||||
- [x] Custom the sorting header
|
- [x] Custom the sorting header
|
||||||
|
- [x] Sort event listener
|
||||||
- [ ] Custom the sort caret
|
- [ ] Custom the sort caret
|
||||||
- [ ] Sort management
|
- [ ] Sort management
|
||||||
- [ ] Multi sort
|
- [ ] Multi sort
|
||||||
|
|
||||||
Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnsort-bool) property on column definitation.
|
Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnsort-bool) property on column definition.
|
||||||
|
|
||||||
## Row Selection
|
## Row Selection
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -81,17 +82,18 @@ 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
|
||||||
- [ ] Select Filter
|
- [x] Select Filter
|
||||||
- [ ] Number Filter
|
- [x] Custom Select Filter
|
||||||
- [ ] Date Filter
|
- [X] Number Filter
|
||||||
|
- [X] Date Filter
|
||||||
- [ ] Array Filter
|
- [ ] 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.
|
||||||
|
|
||||||
Due to no `TableHeaderColumn` so that no `filter` here, please add [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnfilter-object) property on column definitation and [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html#filter-object) prop on `BootstrapTable`.
|
Due to no `TableHeaderColumn` so that no `filter` here, please add [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnfilter-object) property on column definition and [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html#filter-object) prop on `BootstrapTable`.
|
||||||
|
|
||||||
## Cell Edit
|
## Cell Edit
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
* [mode (**required**)](#mode)
|
* [mode (**required**)](#mode)
|
||||||
|
|
||||||
## Optional
|
## Optional
|
||||||
|
* [selected](#selected)
|
||||||
* [style](#style)
|
* [style](#style)
|
||||||
* [classes)](#classes)
|
* [classes)](#classes)
|
||||||
* [bgColor](#bgColor)
|
* [bgColor](#bgColor)
|
||||||
@@ -15,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>
|
||||||
|
|
||||||
@@ -52,6 +55,16 @@ const selectRow = {
|
|||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <a name='selected'>selectRow.selected - [Array]</a>
|
||||||
|
`selectRow.selected` allow you have default selections on table.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
selected: [1, 3] // should be a row keys array
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### <a name='style'>selectRow.style - [Object | Function]</a>
|
### <a name='style'>selectRow.style - [Object | Function]</a>
|
||||||
`selectRow.style` allow you to have custom style on selected rows:
|
`selectRow.style` allow you to have custom style on selected rows:
|
||||||
|
|
||||||
@@ -91,7 +104,7 @@ const selectRow = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### <a name='bgColor'>selectRow.bgColor - [String | Function]</a>
|
### <a name='bgColor'>selectRow.bgColor - [String | Function]</a>
|
||||||
The backgroud color when row is selected
|
The background color when row is selected
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const selectRow = {
|
const selectRow = {
|
||||||
@@ -145,14 +158,42 @@ const selectRow = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### <a name='onSelect'>selectRow.onSelect - [Function]</a>
|
### <a name='selectionRenderer'>selectRow.selectionRenderer - [Function]</a>
|
||||||
This callback function will be called when a row is select/unselect and pass following three arguments:
|
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:
|
||||||
`row`, `isSelect` and `rowIndex`.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const selectRow = {
|
const selectRow = {
|
||||||
mode: 'checkbox',
|
mode: 'checkbox',
|
||||||
onSelect: (row, isSelect, rowIndex) => {
|
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>
|
||||||
|
This callback function will be called when a row is select/unselect and pass following three arguments:
|
||||||
|
`row`, `isSelect`, `rowIndex` and `e`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
onSelect: (row, isSelect, rowIndex, e) => {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -164,7 +205,7 @@ This callback function will be called when select/unselect all and it only work
|
|||||||
```js
|
```js
|
||||||
const selectRow = {
|
const selectRow = {
|
||||||
mode: 'checkbox',
|
mode: 'checkbox',
|
||||||
onSelectAll: (isSelect, results) => {
|
onSelectAll: (isSelect, results, e) => {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const JS_SKIPS = `+(${TEST}|${LIB}|${DIST}|${NODE_MODULES})`;
|
|||||||
|
|
||||||
const STYLE_PKGS = [
|
const STYLE_PKGS = [
|
||||||
'react-bootstrap-table2',
|
'react-bootstrap-table2',
|
||||||
|
'react-bootstrap-table2-filter',
|
||||||
'react-bootstrap-table2-paginator'
|
'react-bootstrap-table2-paginator'
|
||||||
].reduce((pkg, curr) => `${curr}|${pkg}`, '');
|
].reduce((pkg, curr) => `${curr}|${pkg}`, '');
|
||||||
|
|
||||||
@@ -71,9 +72,15 @@ function styles() {
|
|||||||
.pipe(gulp.dest(PKG_PATH));
|
.pipe(gulp.dest(PKG_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
function umd() {
|
function umd(done) {
|
||||||
return gulp.src('./webpack.prod.config.babel.js')
|
gulp.parallel(
|
||||||
.pipe(shell(['webpack --config <%= file.path %>']));
|
() => gulp.src('./webpack/next.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||||
|
() => gulp.src('./webpack/editor.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||||
|
() => gulp.src('./webpack/filter.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||||
|
() => gulp.src('./webpack/overlay.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||||
|
() => gulp.src('./webpack/paginator.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>']))
|
||||||
|
)();
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildJS = gulp.parallel(umd, scripts);
|
const buildJS = gulp.parallel(umd, scripts);
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"storybook": "cd ./packages/react-bootstrap-table2-example && yarn storybook",
|
"storybook": "cd ./packages/react-bootstrap-table2-example && yarn storybook",
|
||||||
"gh-pages:clean": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:clean",
|
"gh-pages:clean": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:clean",
|
||||||
"gh-pages:build": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:build"
|
"gh-pages:build": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:build",
|
||||||
|
"release": "yarn install && yarn build && lerna publish"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -85,7 +86,8 @@
|
|||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"collectCoverageFrom": [
|
"collectCoverageFrom": [
|
||||||
"packages/**/*.js"
|
"packages/*/src/*.js",
|
||||||
|
"packages/*/index.js"
|
||||||
],
|
],
|
||||||
"roots": [
|
"roots": [
|
||||||
"<rootDir>/packages"
|
"<rootDir>/packages"
|
||||||
|
|||||||
@@ -48,14 +48,182 @@ How user save their new editings? We offer two ways:
|
|||||||
* Column Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as bool value)
|
* Column Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as bool value)
|
||||||
* Cell Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as a callback function)
|
* Cell Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as a callback function)
|
||||||
|
|
||||||
## Customize Style/Class
|
## Validation
|
||||||
Currently, we only support the editing cell style/class customization, in the future, we will offer more customizations.
|
|
||||||
|
|
||||||
|
[column.validator](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will help you to work on it!
|
||||||
|
## Customize Style/Class
|
||||||
### Editing Cell
|
### Editing Cell
|
||||||
|
|
||||||
* Customize the editing cell style via [column.editCellStyle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellstyle-object-function)
|
* Customize the editing cell style via [column.editCellStyle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellstyle-object-function)
|
||||||
* Customize the editing cell classname via [column.editCellClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellclasses-string-function)
|
* Customize the editing cell classname via [column.editCellClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellclasses-string-function)
|
||||||
|
|
||||||
## Validation
|
### Editor
|
||||||
|
* Customize the editor style via [column.editorStyle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorstyle-object-function)
|
||||||
|
* Customize the editor classname via [column.editoClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorclasses-string-function)
|
||||||
|
|
||||||
[`column.validator`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will help you to work on it!
|
## Rich Editors
|
||||||
|
`react-bootstrap-table2` have following predefined editor:
|
||||||
|
|
||||||
|
* Text(Default)
|
||||||
|
* Dropdown
|
||||||
|
* Date
|
||||||
|
* Textarea
|
||||||
|
* Checkbox
|
||||||
|
|
||||||
|
In a nutshell, you just only give a [column.editor](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditor-object) and define the `type`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT | Type.TEXTAREA | Type.CHECKBOX | Type.DATE,
|
||||||
|
... // The rest properties will be rendered into the editor's DOM element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
In the following, we go though all the predefined editors:
|
||||||
|
|
||||||
|
### Dropdown Editor
|
||||||
|
Dropdown editor give a select menu to choose a data from a list, the `editor.options` is required property for dropdown editor.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 'A',
|
||||||
|
label: 'A'
|
||||||
|
}, {
|
||||||
|
value: 'B',
|
||||||
|
label: 'B'
|
||||||
|
}, {
|
||||||
|
value: 'C',
|
||||||
|
label: 'C'
|
||||||
|
}, {
|
||||||
|
value: 'D',
|
||||||
|
label: 'D'
|
||||||
|
}, {
|
||||||
|
value: 'E',
|
||||||
|
label: 'E'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Date Editor
|
||||||
|
Date editor is use `<input type="date">`, the configuration is very simple:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'Stock Date',
|
||||||
|
formatter: (cell) => {
|
||||||
|
let dateObj = cell;
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
dateObj = new Date(cell);
|
||||||
|
}
|
||||||
|
return `${('0' + dateObj.getDate()).slice(-2)}/${('0' + (dateObj.getMonth() + 1)).slice(-2)}/${dateObj.getFullYear()}`;
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
type: Type.DATE
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Textarea Editor
|
||||||
|
Textarea editor is use `<input type="textarea">`, user can press `ENTER` to change line and in the `react-bootstrap-table2`, user allow to save result via press `SHIFT` + `ENTER`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'comment',
|
||||||
|
text: 'Product Comments',
|
||||||
|
editor: {
|
||||||
|
type: Type.TEXTAREA
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
### Checkbox Editor
|
||||||
|
Checkbox editor allow you to have a pair value choice, the `editor.value` is required value to represent the actual value for check and uncheck.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'comment',
|
||||||
|
text: 'Product Comments',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customize Editor
|
||||||
|
If you feel above predefined editors are not satisfied to your requirement, you can certainly custom the editor via [column.editorRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorrenderer-function). It accept a function and pass following arguments when function called:
|
||||||
|
|
||||||
|
* `editorProps`: Some useful attributes you can use on DOM editor, like class, style etc.
|
||||||
|
* `value`: Current cell value
|
||||||
|
* `row`: Current row data
|
||||||
|
* `column`: Current column definition
|
||||||
|
* `rowIndex`: Current row index
|
||||||
|
* `columnIndex`: Current column index
|
||||||
|
|
||||||
|
> Note when implement a custom React editor component, this component should have a **getValue** function which return current value on editor
|
||||||
|
|
||||||
|
> Note when you want to save value, you can call **editorProps.onUpdate** function
|
||||||
|
|
||||||
|
Following is a short example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) => (
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />
|
||||||
|
)
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import wrapperFactory from './src/wrapper';
|
import wrapperFactory from './src/wrapper';
|
||||||
import editingCellFactory from './src/editing-cell';
|
import editingCellFactory from './src/editing-cell';
|
||||||
import {
|
import {
|
||||||
|
EDITTYPE,
|
||||||
CLICK_TO_CELL_EDIT,
|
CLICK_TO_CELL_EDIT,
|
||||||
DBCLICK_TO_CELL_EDIT,
|
DBCLICK_TO_CELL_EDIT,
|
||||||
DELAY_FOR_DBCLICK
|
DELAY_FOR_DBCLICK
|
||||||
@@ -14,3 +15,5 @@ export default (options = {}) => ({
|
|||||||
DELAY_FOR_DBCLICK,
|
DELAY_FOR_DBCLICK,
|
||||||
options
|
options
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const Type = EDITTYPE;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-editor",
|
"name": "react-bootstrap-table2-editor",
|
||||||
"version": "0.1.1",
|
"version": "0.2.1",
|
||||||
"description": "it's the editor addon for react-bootstrap-table2",
|
"description": "it's the editor addon for react-bootstrap-table2",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
61
packages/react-bootstrap-table2-editor/src/checkbox-editor.js
vendored
Normal file
61
packages/react-bootstrap-table2-editor/src/checkbox-editor.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class CheckBoxEditor extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
checked: props.defaultValue.toString() === props.value.split(':')[0]
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.checkbox.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
const [positive, negative] = this.props.value.split(':');
|
||||||
|
return this.checkbox.checked ? positive : negative;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(e) {
|
||||||
|
if (this.props.onChange) this.props.onChange(e);
|
||||||
|
const { target } = e;
|
||||||
|
this.setState(() => ({ checked: target.checked }));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
|
const editorClass = cs('editor edit-chseckbox checkbox', className);
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ node => this.checkbox = node }
|
||||||
|
type="checkbox"
|
||||||
|
className={ editorClass }
|
||||||
|
{ ...rest }
|
||||||
|
checked={ this.state.checked }
|
||||||
|
onChange={ this.handleChange }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBoxEditor.propTypes = {
|
||||||
|
className: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.object
|
||||||
|
]),
|
||||||
|
value: PropTypes.string,
|
||||||
|
defaultValue: PropTypes.any,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
};
|
||||||
|
CheckBoxEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
value: 'on:off',
|
||||||
|
defaultValue: false,
|
||||||
|
onChange: undefined
|
||||||
|
};
|
||||||
|
export default CheckBoxEditor;
|
||||||
@@ -2,3 +2,11 @@ export const TIME_TO_CLOSE_MESSAGE = 3000;
|
|||||||
export const DELAY_FOR_DBCLICK = 200;
|
export const DELAY_FOR_DBCLICK = 200;
|
||||||
export const CLICK_TO_CELL_EDIT = 'click';
|
export const CLICK_TO_CELL_EDIT = 'click';
|
||||||
export const DBCLICK_TO_CELL_EDIT = 'dbclick';
|
export const DBCLICK_TO_CELL_EDIT = 'dbclick';
|
||||||
|
|
||||||
|
export const EDITTYPE = {
|
||||||
|
TEXT: 'text',
|
||||||
|
SELECT: 'select',
|
||||||
|
TEXTAREA: 'textarea',
|
||||||
|
CHECKBOX: 'checkbox',
|
||||||
|
DATE: 'date'
|
||||||
|
};
|
||||||
|
|||||||
42
packages/react-bootstrap-table2-editor/src/date-editor.js
vendored
Normal file
42
packages/react-bootstrap-table2-editor/src/date-editor.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class DateEditor extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
this.date.valueAsDate = new Date(defaultValue);
|
||||||
|
this.date.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.date.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
|
const editorClass = cs('form-control editor edit-date', className);
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ node => this.date = node }
|
||||||
|
type="date"
|
||||||
|
className={ editorClass }
|
||||||
|
{ ...rest }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateEditor.propTypes = {
|
||||||
|
className: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.object
|
||||||
|
]),
|
||||||
|
defaultValue: PropTypes.string
|
||||||
|
};
|
||||||
|
DateEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
defaultValue: ''
|
||||||
|
};
|
||||||
|
export default DateEditor;
|
||||||
61
packages/react-bootstrap-table2-editor/src/dropdown-editor.js
vendored
Normal file
61
packages/react-bootstrap-table2-editor/src/dropdown-editor.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class DropDownEditor extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
this.select.value = defaultValue;
|
||||||
|
this.select.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.select.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, options, ...rest } = this.props;
|
||||||
|
const editorClass = cs('form-control editor edit-select', className);
|
||||||
|
|
||||||
|
const attr = {
|
||||||
|
...rest,
|
||||||
|
className: editorClass
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
{ ...attr }
|
||||||
|
ref={ node => this.select = node }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
|
>
|
||||||
|
{
|
||||||
|
options.map(({ label, value }) => (
|
||||||
|
<option key={ value } value={ value }>{ label }</option>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDownEditor.propTypes = {
|
||||||
|
defaultValue: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number
|
||||||
|
]),
|
||||||
|
className: PropTypes.string,
|
||||||
|
style: PropTypes.object,
|
||||||
|
options: PropTypes.oneOfType([
|
||||||
|
PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
label: PropTypes.string,
|
||||||
|
value: PropTypes.any
|
||||||
|
}))
|
||||||
|
]).isRequired
|
||||||
|
};
|
||||||
|
DropDownEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
defaultValue: '',
|
||||||
|
style: {}
|
||||||
|
};
|
||||||
|
export default DropDownEditor;
|
||||||
@@ -6,15 +6,21 @@ import React, { Component } from 'react';
|
|||||||
import cs from 'classnames';
|
import cs from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import DropdownEditor from './dropdown-editor';
|
||||||
|
import TextAreaEditor from './textarea-editor';
|
||||||
|
import CheckBoxEditor from './checkbox-editor';
|
||||||
|
import DateEditor from './date-editor';
|
||||||
import TextEditor from './text-editor';
|
import TextEditor from './text-editor';
|
||||||
import EditorIndicator from './editor-indicator';
|
import EditorIndicator from './editor-indicator';
|
||||||
import { TIME_TO_CLOSE_MESSAGE } from './const';
|
import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const';
|
||||||
|
|
||||||
export default _ =>
|
export default _ =>
|
||||||
class EditingCell extends Component {
|
class EditingCell extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
row: PropTypes.object.isRequired,
|
row: PropTypes.object.isRequired,
|
||||||
|
rowIndex: PropTypes.number.isRequired,
|
||||||
column: PropTypes.object.isRequired,
|
column: PropTypes.object.isRequired,
|
||||||
|
columnIndex: PropTypes.number.isRequired,
|
||||||
onUpdate: PropTypes.func.isRequired,
|
onUpdate: PropTypes.func.isRequired,
|
||||||
onEscape: PropTypes.func.isRequired,
|
onEscape: PropTypes.func.isRequired,
|
||||||
timeToCloseMessage: PropTypes.number,
|
timeToCloseMessage: PropTypes.number,
|
||||||
@@ -71,8 +77,8 @@ export default _ =>
|
|||||||
}, timeToCloseMessage);
|
}, timeToCloseMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeComplete(row, column, newValue) {
|
beforeComplete(newValue) {
|
||||||
const { onUpdate } = this.props;
|
const { onUpdate, row, column } = this.props;
|
||||||
if (_.isFunction(column.validator)) {
|
if (_.isFunction(column.validator)) {
|
||||||
const validateForm = column.validator(newValue, row, column);
|
const validateForm = column.validator(newValue, row, column);
|
||||||
if (_.isObject(validateForm) && !validateForm.valid) {
|
if (_.isObject(validateForm) && !validateForm.valid) {
|
||||||
@@ -87,28 +93,20 @@ export default _ =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleBlur() {
|
handleBlur() {
|
||||||
const { onEscape, blurToSave, row, column } = this.props;
|
const { onEscape, blurToSave } = this.props;
|
||||||
if (blurToSave) {
|
if (blurToSave) {
|
||||||
const value = this.editor.text.value;
|
this.beforeComplete(this.editor.getValue());
|
||||||
if (!_.isDefined(value)) {
|
|
||||||
// TODO: for other custom or embed editor
|
|
||||||
}
|
|
||||||
this.beforeComplete(row, column, value);
|
|
||||||
} else {
|
} else {
|
||||||
onEscape();
|
onEscape();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
const { onEscape, row, column } = this.props;
|
const { onEscape } = this.props;
|
||||||
if (e.keyCode === 27) { // ESC
|
if (e.keyCode === 27) { // ESC
|
||||||
onEscape();
|
onEscape();
|
||||||
} else if (e.keyCode === 13) { // ENTER
|
} else if (e.keyCode === 13) { // ENTER
|
||||||
const value = e.currentTarget.value;
|
this.beforeComplete(this.editor.getValue());
|
||||||
if (!_.isDefined(value)) {
|
|
||||||
// TODO: for other custom or embed editor
|
|
||||||
}
|
|
||||||
this.beforeComplete(row, column, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,31 +120,73 @@ export default _ =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { invalidMessage } = this.state;
|
let editor;
|
||||||
const { row, column, className, style } = this.props;
|
const { row, column, className, style, rowIndex, columnIndex } = this.props;
|
||||||
const { dataField } = column;
|
const { dataField } = column;
|
||||||
|
|
||||||
const value = _.get(row, dataField);
|
const value = _.get(row, dataField);
|
||||||
const editorAttrs = {
|
const hasError = _.isDefined(this.state.invalidMessage);
|
||||||
|
|
||||||
|
let customEditorClass = column.editorClasses || '';
|
||||||
|
if (_.isFunction(column.editorClasses)) {
|
||||||
|
customEditorClass = column.editorClasses(value, row, rowIndex, columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
let editorStyle = column.editorStyle || {};
|
||||||
|
if (_.isFunction(column.editorStyle)) {
|
||||||
|
editorStyle = column.editorStyle(value, row, rowIndex, columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
const editorClass = cs({
|
||||||
|
animated: hasError,
|
||||||
|
shake: hasError
|
||||||
|
}, customEditorClass);
|
||||||
|
|
||||||
|
let editorProps = {
|
||||||
|
ref: node => this.editor = node,
|
||||||
|
defaultValue: value,
|
||||||
|
style: editorStyle,
|
||||||
|
className: editorClass,
|
||||||
onKeyDown: this.handleKeyDown,
|
onKeyDown: this.handleKeyDown,
|
||||||
onBlur: this.handleBlur
|
onBlur: this.handleBlur
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasError = _.isDefined(invalidMessage);
|
const isDefaultEditorDefined = _.isObject(column.editor);
|
||||||
const editorClass = hasError ? cs('animated', 'shake') : null;
|
|
||||||
|
if (isDefaultEditorDefined) {
|
||||||
|
editorProps = {
|
||||||
|
...editorProps,
|
||||||
|
...column.editor
|
||||||
|
};
|
||||||
|
} else if (_.isFunction(column.editorRenderer)) {
|
||||||
|
editorProps = {
|
||||||
|
...editorProps,
|
||||||
|
onUpdate: this.beforeComplete
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isFunction(column.editorRenderer)) {
|
||||||
|
editor = column.editorRenderer(editorProps, value, row, column, rowIndex, columnIndex);
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.SELECT) {
|
||||||
|
editor = <DropdownEditor { ...editorProps } />;
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.TEXTAREA) {
|
||||||
|
editor = <TextAreaEditor { ...editorProps } />;
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.CHECKBOX) {
|
||||||
|
editor = <CheckBoxEditor { ...editorProps } />;
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.DATE) {
|
||||||
|
editor = <DateEditor { ...editorProps } />;
|
||||||
|
} else {
|
||||||
|
editor = <TextEditor { ...editorProps } />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<td
|
<td
|
||||||
className={ cs('react-bootstrap-table-editing-cell', className) }
|
className={ cs('react-bootstrap-table-editing-cell', className) }
|
||||||
style={ style }
|
style={ style }
|
||||||
onClick={ this.handleClick }
|
onClick={ this.handleClick }
|
||||||
>
|
>
|
||||||
<TextEditor
|
{ editor }
|
||||||
ref={ node => this.editor = node }
|
{ hasError ? <EditorIndicator invalidMessage={ this.state.invalidMessage } /> : null }
|
||||||
defaultValue={ value }
|
|
||||||
className={ editorClass }
|
|
||||||
{ ...editorAttrs }
|
|
||||||
/>
|
|
||||||
{ hasError ? <EditorIndicator invalidMessage={ invalidMessage } /> : null }
|
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ class TextEditor extends Component {
|
|||||||
this.text.focus();
|
this.text.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.text.value;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { defaultValue, className, ...rest } = this.props;
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
const editorClass = cs('form-control editor edit-text', className);
|
const editorClass = cs('form-control editor edit-text', className);
|
||||||
@@ -32,9 +36,10 @@ TextEditor.propTypes = {
|
|||||||
defaultValue: PropTypes.oneOfType([
|
defaultValue: PropTypes.oneOfType([
|
||||||
PropTypes.string,
|
PropTypes.string,
|
||||||
PropTypes.number
|
PropTypes.number
|
||||||
]).isRequired
|
])
|
||||||
};
|
};
|
||||||
TextEditor.defaultProps = {
|
TextEditor.defaultProps = {
|
||||||
className: null
|
className: null,
|
||||||
|
defaultValue: ''
|
||||||
};
|
};
|
||||||
export default TextEditor;
|
export default TextEditor;
|
||||||
|
|||||||
60
packages/react-bootstrap-table2-editor/src/textarea-editor.js
vendored
Normal file
60
packages/react-bootstrap-table2-editor/src/textarea-editor.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class TextAreaEditor extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
this.text.value = defaultValue;
|
||||||
|
this.text.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.text.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown(e) {
|
||||||
|
if (e.keyCode === 13 && !e.shiftKey) return;
|
||||||
|
if (this.props.onKeyDown) {
|
||||||
|
this.props.onKeyDown(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
|
const editorClass = cs('form-control editor edit-textarea', className);
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
ref={ node => this.text = node }
|
||||||
|
type="textarea"
|
||||||
|
className={ editorClass }
|
||||||
|
{ ...rest }
|
||||||
|
onKeyDown={ this.handleKeyDown }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAreaEditor.propTypes = {
|
||||||
|
className: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.object
|
||||||
|
]),
|
||||||
|
defaultValue: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number
|
||||||
|
]),
|
||||||
|
onKeyDown: PropTypes.func
|
||||||
|
};
|
||||||
|
TextAreaEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
defaultValue: '',
|
||||||
|
onKeyDown: undefined
|
||||||
|
};
|
||||||
|
export default TextAreaEditor;
|
||||||
@@ -6,7 +6,12 @@ import { shallow, mount } from 'enzyme';
|
|||||||
|
|
||||||
import _ from 'react-bootstrap-table-next/src/utils';
|
import _ from 'react-bootstrap-table-next/src/utils';
|
||||||
import editingCellFactory from '../src/editing-cell';
|
import editingCellFactory from '../src/editing-cell';
|
||||||
|
import * as constants from '../src/const';
|
||||||
import TextEditor from '../src/text-editor';
|
import TextEditor from '../src/text-editor';
|
||||||
|
import DateEditor from '../src/date-editor';
|
||||||
|
import DropDownEditor from '../src/dropdown-editor';
|
||||||
|
import TextAreaEditor from '../src/textarea-editor';
|
||||||
|
import CheckBoxEditor from '../src/checkbox-editor';
|
||||||
import EditorIndicator from '../src/editor-indicator';
|
import EditorIndicator from '../src/editor-indicator';
|
||||||
|
|
||||||
const EditingCell = editingCellFactory(_);
|
const EditingCell = editingCellFactory(_);
|
||||||
@@ -28,6 +33,9 @@ describe('EditingCell', () => {
|
|||||||
name: 'A'
|
name: 'A'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const rowIndex = 1;
|
||||||
|
const columnIndex = 1;
|
||||||
|
|
||||||
let column = {
|
let column = {
|
||||||
dataField: 'id',
|
dataField: 'id',
|
||||||
text: 'ID'
|
text: 'ID'
|
||||||
@@ -36,9 +44,11 @@ describe('EditingCell', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
onEscape = sinon.stub();
|
onEscape = sinon.stub();
|
||||||
onUpdate = sinon.stub();
|
onUpdate = sinon.stub();
|
||||||
wrapper = shallow(
|
wrapper = mount(
|
||||||
<EditingCell
|
<EditingCell
|
||||||
row={ row }
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
column={ column }
|
column={ column }
|
||||||
onUpdate={ onUpdate }
|
onUpdate={ onUpdate }
|
||||||
onEscape={ onEscape }
|
onEscape={ onEscape }
|
||||||
@@ -58,7 +68,7 @@ describe('EditingCell', () => {
|
|||||||
expect(textEditor.props().defaultValue).toEqual(row[column.dataField]);
|
expect(textEditor.props().defaultValue).toEqual(row[column.dataField]);
|
||||||
expect(textEditor.props().onKeyDown).toBeDefined();
|
expect(textEditor.props().onKeyDown).toBeDefined();
|
||||||
expect(textEditor.props().onBlur).toBeDefined();
|
expect(textEditor.props().onBlur).toBeDefined();
|
||||||
expect(textEditor.props().className).toBeNull();
|
expect(textEditor.props().className).toEqual('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not render EditorIndicator due to state.invalidMessage is null', () => {
|
it('should not render EditorIndicator due to state.invalidMessage is null', () => {
|
||||||
@@ -69,7 +79,8 @@ describe('EditingCell', () => {
|
|||||||
it('when press ENTER on TextEditor should call onUpdate correctly', () => {
|
it('when press ENTER on TextEditor should call onUpdate correctly', () => {
|
||||||
const newValue = 'test';
|
const newValue = 'test';
|
||||||
const textEditor = wrapper.find(TextEditor);
|
const textEditor = wrapper.find(TextEditor);
|
||||||
textEditor.simulate('keyDown', { keyCode: 13, currentTarget: { value: newValue } });
|
sinon.stub(textEditor.instance(), 'getValue').returns(newValue);
|
||||||
|
textEditor.simulate('keyDown', { keyCode: 13 });
|
||||||
expect(onUpdate.callCount).toBe(1);
|
expect(onUpdate.callCount).toBe(1);
|
||||||
expect(onUpdate.calledWith(row, column, newValue)).toBe(true);
|
expect(onUpdate.calledWith(row, column, newValue)).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -92,6 +103,8 @@ describe('EditingCell', () => {
|
|||||||
wrapper = shallow(
|
wrapper = shallow(
|
||||||
<EditingCell
|
<EditingCell
|
||||||
row={ row }
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
column={ column }
|
column={ column }
|
||||||
onUpdate={ onUpdate }
|
onUpdate={ onUpdate }
|
||||||
onEscape={ onEscape }
|
onEscape={ onEscape }
|
||||||
@@ -112,6 +125,8 @@ describe('EditingCell', () => {
|
|||||||
wrapper = shallow(
|
wrapper = shallow(
|
||||||
<EditingCell
|
<EditingCell
|
||||||
row={ row }
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
column={ column }
|
column={ column }
|
||||||
onUpdate={ onUpdate }
|
onUpdate={ onUpdate }
|
||||||
onEscape={ onEscape }
|
onEscape={ onEscape }
|
||||||
@@ -126,12 +141,140 @@ describe('EditingCell', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('if column.editorClasses is defined', () => {
|
||||||
|
let columnWithEditorClasses;
|
||||||
|
const classes = 'test test1';
|
||||||
|
|
||||||
|
describe('and it is a function', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
columnWithEditorClasses = {
|
||||||
|
...column,
|
||||||
|
editorClasses: jest.fn(() => classes)
|
||||||
|
};
|
||||||
|
wrapper = shallow(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ columnWithEditorClasses }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render TextEditor with correct props', () => {
|
||||||
|
const textEditor = wrapper.find(TextEditor);
|
||||||
|
expect(textEditor.props().className).toEqual(classes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call column.editorClasses correctly', () => {
|
||||||
|
expect(columnWithEditorClasses.editorClasses).toHaveBeenCalledTimes(1);
|
||||||
|
expect(columnWithEditorClasses.editorClasses).toHaveBeenCalledWith(
|
||||||
|
_.get(row, column.dataField),
|
||||||
|
row,
|
||||||
|
rowIndex,
|
||||||
|
columnIndex
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and it is a string', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
columnWithEditorClasses = {
|
||||||
|
...column,
|
||||||
|
editorClasses: classes
|
||||||
|
};
|
||||||
|
wrapper = shallow(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ columnWithEditorClasses }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render TextEditor with correct props', () => {
|
||||||
|
const textEditor = wrapper.find(TextEditor);
|
||||||
|
expect(textEditor.props().className).toEqual(classes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editorStyle is defined', () => {
|
||||||
|
let columnWithEditorStyle;
|
||||||
|
const style = { color: 'red' };
|
||||||
|
|
||||||
|
describe('and it is a function', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
columnWithEditorStyle = {
|
||||||
|
...column,
|
||||||
|
editorStyle: jest.fn(() => style)
|
||||||
|
};
|
||||||
|
wrapper = shallow(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ columnWithEditorStyle }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render TextEditor with correct props', () => {
|
||||||
|
const textEditor = wrapper.find(TextEditor);
|
||||||
|
expect(textEditor.props().style).toEqual(style);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call column.editorStyle correctly', () => {
|
||||||
|
expect(columnWithEditorStyle.editorStyle).toHaveBeenCalledTimes(1);
|
||||||
|
expect(columnWithEditorStyle.editorStyle).toHaveBeenCalledWith(
|
||||||
|
_.get(row, column.dataField),
|
||||||
|
row,
|
||||||
|
rowIndex,
|
||||||
|
columnIndex
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and it is an object', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
columnWithEditorStyle = {
|
||||||
|
...column,
|
||||||
|
editorStyle: style
|
||||||
|
};
|
||||||
|
wrapper = shallow(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ columnWithEditorStyle }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render TextEditor with correct props', () => {
|
||||||
|
const textEditor = wrapper.find(TextEditor);
|
||||||
|
expect(textEditor.props().style).toEqual(style);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('if blurToSave prop is true', () => {
|
describe('if blurToSave prop is true', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = mount(
|
wrapper = mount(
|
||||||
<TableRowWrapper>
|
<TableRowWrapper>
|
||||||
<EditingCell
|
<EditingCell
|
||||||
row={ row }
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
column={ column }
|
column={ column }
|
||||||
onUpdate={ onUpdate }
|
onUpdate={ onUpdate }
|
||||||
onEscape={ onEscape }
|
onEscape={ onEscape }
|
||||||
@@ -167,12 +310,14 @@ describe('EditingCell', () => {
|
|||||||
wrapper = mount(
|
wrapper = mount(
|
||||||
<EditingCell
|
<EditingCell
|
||||||
row={ row }
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
column={ column }
|
column={ column }
|
||||||
onUpdate={ onUpdate }
|
onUpdate={ onUpdate }
|
||||||
onEscape={ onEscape }
|
onEscape={ onEscape }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
wrapper.instance().beforeComplete(row, column, newValue);
|
wrapper.instance().beforeComplete(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call column.validator successfully', () => {
|
it('should call column.validator successfully', () => {
|
||||||
@@ -218,7 +363,17 @@ describe('EditingCell', () => {
|
|||||||
text: 'ID',
|
text: 'ID',
|
||||||
validator: validatorCallBack
|
validator: validatorCallBack
|
||||||
};
|
};
|
||||||
wrapper.instance().beforeComplete(row, column, newValue);
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
wrapper.instance().beforeComplete(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call column.validator successfully', () => {
|
it('should call column.validator successfully', () => {
|
||||||
@@ -231,4 +386,156 @@ describe('EditingCell', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('if column.editorRenderer is defined', () => {
|
||||||
|
const TestEditor = () => <input type="text" />;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editorRenderer: sinon.stub().returns(<TestEditor />)
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call column.editorRenderer correctly', () => {
|
||||||
|
expect(column.editorRenderer.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render correctly', () => {
|
||||||
|
expect(wrapper.find(TestEditor)).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is select', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 1,
|
||||||
|
label: 'A'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render dropdown editor successfully', () => {
|
||||||
|
const editor = wrapper.find(DropDownEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
expect(editor.props().options).toEqual(column.editor.options);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is textarea', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.TEXTAREA
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render textarea editor successfully', () => {
|
||||||
|
const editor = wrapper.find(TextAreaEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is checkbox', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.CHECKBOX
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render checkbox editor successfully', () => {
|
||||||
|
const editor = wrapper.find(CheckBoxEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is date', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.DATE
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render date editor successfully', () => {
|
||||||
|
const editor = wrapper.find(DateEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filt
|
|||||||
const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js');
|
const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js');
|
||||||
const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style');
|
const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style');
|
||||||
const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style');
|
const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style');
|
||||||
|
const filterStylePath = path.join(__dirname, '../../react-bootstrap-table2-filter/style');
|
||||||
const storyPath = path.join(__dirname, '../stories');
|
const storyPath = path.join(__dirname, '../stories');
|
||||||
const examplesPath = path.join(__dirname, '../examples');
|
const examplesPath = path.join(__dirname, '../examples');
|
||||||
const srcPath = path.join(__dirname, '../src');
|
const srcPath = path.join(__dirname, '../src');
|
||||||
@@ -40,7 +41,7 @@ const loaders = [{
|
|||||||
}, {
|
}, {
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||||
include: [storyPath, sourceStylePath, paginationStylePath],
|
include: [storyPath, sourceStylePath, paginationStylePath, filterStylePath],
|
||||||
}, {
|
}, {
|
||||||
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
|
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
|
||||||
loader: 'url-loader?limit=100000',
|
loader: 'url-loader?limit=100000',
|
||||||
|
|||||||
52
packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js
vendored
Normal file
52
packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.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 id="bar" keyField='id' data={ products } columns={ columns } />
|
||||||
|
<BootstrapTable classes="foo" keyField='id' data={ products } columns={ columns } />
|
||||||
|
<BootstrapTable wrapperClasses="boo" keyField="id" data={ products } columns={ columns } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h4> Customized table ID </h4>
|
||||||
|
<BootstrapTable id="bar" keyField="id" data={ products } columns={ columns } />
|
||||||
|
|
||||||
|
<h4> Customized table className </h4>
|
||||||
|
<BootstrapTable classes="foo" keyField="id" data={ products } columns={ columns } />
|
||||||
|
|
||||||
|
<h4> Customized wrapper className </h4>
|
||||||
|
<BootstrapTable wrapperClasses="boo" keyField="id" data={ products } columns={ columns } />
|
||||||
|
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
64
packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js
vendored
Normal file
64
packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { todosGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const todos = todosGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Todo ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'todo',
|
||||||
|
text: 'Todo Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Todo ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'todo',
|
||||||
|
text: 'Todo Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ todos }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ todos }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
130
packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js
vendored
Normal file
130
packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js
vendored
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
/* eslint no-unused-vars: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator();
|
||||||
|
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) => (
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />
|
||||||
|
)
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
editorRenderer: (editorProps, value, row, rowIndex, columnIndex) => (
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />
|
||||||
|
)
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
77
packages/react-bootstrap-table2-example/examples/cell-edit/date-editor-table.js
vendored
Normal file
77
packages/react-bootstrap-table2-example/examples/cell-edit/date-editor-table.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* eslint prefer-template: 0 */
|
||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { stockGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const stocks = stockGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'Stock Date',
|
||||||
|
formatter: (cell) => {
|
||||||
|
let dateObj = cell;
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
dateObj = new Date(cell);
|
||||||
|
}
|
||||||
|
return `${('0' + dateObj.getDate()).slice(-2)}/${('0' + (dateObj.getMonth() + 1)).slice(-2)}/${dateObj.getFullYear()}`;
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
type: Type.DATE
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'Stock Date',
|
||||||
|
formatter: (cell) => {
|
||||||
|
let dateObj = cell;
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
dateObj = new Date(cell);
|
||||||
|
}
|
||||||
|
return \`$\{('0' + dateObj.getDate()).slice(-2)}/$\{('0' + (dateObj.getMonth() + 1)).slice(-2)}/$\{dateObj.getFullYear()}\`;
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
type: Type.DATE
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
100
packages/react-bootstrap-table2-example/examples/cell-edit/dropdown-editor-table.js
vendored
Normal file
100
packages/react-bootstrap-table2-example/examples/cell-edit/dropdown-editor-table.js
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { jobsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const jobs = jobsGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 'A',
|
||||||
|
label: 'A'
|
||||||
|
}, {
|
||||||
|
value: 'B',
|
||||||
|
label: 'B'
|
||||||
|
}, {
|
||||||
|
value: 'C',
|
||||||
|
label: 'C'
|
||||||
|
}, {
|
||||||
|
value: 'D',
|
||||||
|
label: 'D'
|
||||||
|
}, {
|
||||||
|
value: 'E',
|
||||||
|
label: 'E'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 'A',
|
||||||
|
label: 'A'
|
||||||
|
}, {
|
||||||
|
value: 'B',
|
||||||
|
label: 'B'
|
||||||
|
}, {
|
||||||
|
value: 'C',
|
||||||
|
label: 'C'
|
||||||
|
}, {
|
||||||
|
value: 'D',
|
||||||
|
label: 'D'
|
||||||
|
}, {
|
||||||
|
value: 'E',
|
||||||
|
label: 'E'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
61
packages/react-bootstrap-table2-example/examples/cell-edit/editor-class-table.js
vendored
Normal file
61
packages/react-bootstrap-table2-example/examples/cell-edit/editor-class-table.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* eslint no-unused-vars: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
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',
|
||||||
|
editorClasses: 'editing-name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
editorClasses: (cell, row, rowIndex, colIndex) =>
|
||||||
|
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
editorClasses: 'editing-name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
editorClasses: (cell, row, rowIndex, colIndex) =>
|
||||||
|
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
69
packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js
vendored
Normal file
69
packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/* eslint no-unused-vars: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
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',
|
||||||
|
editorStyle: {
|
||||||
|
backgroundColor: '#20B2AA'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
editorStyle: (cell, row, rowIndex, colIndex) => {
|
||||||
|
const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF';
|
||||||
|
return { backgroundColor };
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
editorStyle: {
|
||||||
|
backgroundColor: '#20B2AA'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
editorStyle: (cell, row, rowIndex, colIndex) => {
|
||||||
|
const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF';
|
||||||
|
return { backgroundColor };
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
68
packages/react-bootstrap-table2-example/examples/cell-edit/textarea-editor-table.js
vendored
Normal file
68
packages/react-bootstrap-table2-example/examples/cell-edit/textarea-editor-table.js
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { jobsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const jobs = jobsGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.TEXTAREA
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.TEXTAREA
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
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>
|
||||||
|
);
|
||||||
74
packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js
vendored
Normal file
74
packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter({
|
||||||
|
options: [2100, 2103, 2105],
|
||||||
|
delay: 600,
|
||||||
|
placeholder: 'custom placeholder',
|
||||||
|
withoutEmptyComparatorOption: true,
|
||||||
|
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
|
||||||
|
style: { display: 'inline-grid' },
|
||||||
|
className: 'custom-numberfilter-class',
|
||||||
|
comparatorStyle: { backgroundColor: 'antiquewhite' },
|
||||||
|
comparatorClassName: 'custom-comparator-class',
|
||||||
|
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' },
|
||||||
|
numberClassName: 'custom-number-class'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter({
|
||||||
|
options: [2100, 2103, 2105],
|
||||||
|
delay: 600,
|
||||||
|
placeholder: 'custom placeholder',
|
||||||
|
withoutEmptyComparatorOption: true,
|
||||||
|
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
|
||||||
|
style: { display: 'inline-grid' },
|
||||||
|
className: 'custom-numberfilter-class',
|
||||||
|
comparatorStyle: { backgroundColor: 'antiquewhite' },
|
||||||
|
comparatorClassName: 'custom-comparator-class',
|
||||||
|
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' },
|
||||||
|
numberClassName: 'custom-number-class'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<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-select-filter.js
vendored
Normal file
80
packages/react-bootstrap-table2-example/examples/column-filter/custom-select-filter.js
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
0: 'good',
|
||||||
|
1: 'Bad',
|
||||||
|
2: 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quailty',
|
||||||
|
formatter: cell => selectOptions[cell],
|
||||||
|
filter: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
withoutEmptyOption: true,
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'pink'
|
||||||
|
},
|
||||||
|
className: 'test-classname',
|
||||||
|
datamycustomattr: 'datamycustomattr'
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } 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: selectFilter({
|
||||||
|
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>
|
||||||
|
);
|
||||||
54
packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js
vendored
Normal file
54
packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter({
|
||||||
|
defaultValue: { number: 2103, comparator: Comparator.GT }
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter({
|
||||||
|
defaultValue: { number: 2103, comparator: Comparator.GT }
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<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>
|
||||||
|
);
|
||||||
50
packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js
vendored
Normal file
50
packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
<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>
|
||||||
|
);
|
||||||
85
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js
vendored
Normal file
85
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
let priceFilter;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter({
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// pricerFilter was assigned once the component has been mounted.
|
||||||
|
priceFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
priceFilter({
|
||||||
|
number: 2103,
|
||||||
|
comparator: Comparator.GT
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
let priceFilter;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter({
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// pricerFilter was assigned once the component has been mounted.
|
||||||
|
priceFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
priceFilter({
|
||||||
|
number: 2103,
|
||||||
|
comparator: Comparator.GT
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter all columns which is greater than 2103 </button>
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter all columns which is greater than 2103 </button>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
96
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js
vendored
Normal file
96
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
let 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: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// qualityFilter was assigned once the component has been mounted.
|
||||||
|
qualityFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
qualityFilter(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } 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: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// qualityFilter was assigned once the component has been mounted.
|
||||||
|
qualityFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
qualityFilter(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }>{' filter columns by option "good" '}</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" '}</button>
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
81
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js
vendored
Normal file
81
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
let nameFilter;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter({
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// nameFilter was assigned once the component has been mounted.
|
||||||
|
nameFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: textFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
nameFilter(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
let nameFilter;
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter({
|
||||||
|
getFilter: (filter) => {
|
||||||
|
// nameFilter was assigned once the component has been mounted.
|
||||||
|
nameFilter = filter;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: textFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
nameFilter(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter columns by 0 </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 0 </button>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
70
packages/react-bootstrap-table2-example/examples/column-filter/select-filter-default-value.js
vendored
Normal file
70
packages/react-bootstrap-table2-example/examples/column-filter/select-filter-default-value.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
0: 'good',
|
||||||
|
1: 'Bad',
|
||||||
|
2: 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quailty',
|
||||||
|
formatter: cell => selectOptions[cell],
|
||||||
|
filter: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
defaultValue: 2
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } 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: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
defaultValue: 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>
|
||||||
|
);
|
||||||
69
packages/react-bootstrap-table2-example/examples/column-filter/select-filter-like-comparator.js
vendored
Normal file
69
packages/react-bootstrap-table2-example/examples/column-filter/select-filter-like-comparator.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(6);
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
'03': '03',
|
||||||
|
'04': '04',
|
||||||
|
'01': '01'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
comparator: Comparator.LIKE // default is Comparator.EQ
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
'03': '03',
|
||||||
|
'04': '04',
|
||||||
|
'01': '01'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: selectFilter({
|
||||||
|
options: selectOptions,
|
||||||
|
comparator: Comparator.LIKE // default is Comparator.EQ
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Select Filter with LIKE Comparator</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
68
packages/react-bootstrap-table2-example/examples/column-filter/select-filter.js
vendored
Normal file
68
packages/react-bootstrap-table2-example/examples/column-filter/select-filter.js
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator(6);
|
||||||
|
|
||||||
|
const selectOptions = {
|
||||||
|
0: 'good',
|
||||||
|
1: 'Bad',
|
||||||
|
2: 'unknown'
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quailty',
|
||||||
|
formatter: cell => selectOptions[cell],
|
||||||
|
filter: selectFilter({
|
||||||
|
options: selectOptions
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { selectFilter } 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: selectFilter({
|
||||||
|
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>
|
||||||
|
);
|
||||||
51
packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js
vendored
Normal file
51
packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsGenerator(8);
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter({ caseSensitive: true })
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
filter: textFilter({ caseSensitive: true })
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Product Name is case sensitive</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
filter={ filterFactory() }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -28,7 +28,7 @@ import BootstrapTable from 'react-bootstrap-table-next';
|
|||||||
const columns = [{
|
const columns = [{
|
||||||
dataField: 'id',
|
dataField: 'id',
|
||||||
text: 'Product ID',
|
text: 'Product ID',
|
||||||
events: {
|
headerEvents: {
|
||||||
onClick: () => alert('Click on Product ID header column')
|
onClick: () => alert('Click on Product ID header column')
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -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',
|
||||||
@@ -65,6 +80,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
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
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>
|
||||||
|
);
|
||||||
59
packages/react-bootstrap-table2-example/examples/row-selection/default-select.js
vendored
Normal file
59
packages/react-bootstrap-table2-example/examples/row-selection/default-select.js
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
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 selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true,
|
||||||
|
selected: [1, 3]
|
||||||
|
};
|
||||||
|
|
||||||
|
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'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true,
|
||||||
|
selected: [1, 3]
|
||||||
|
};
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField='id'
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
selectRow={ selectRow }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -22,14 +22,16 @@ const columns = [{
|
|||||||
const selectRow = {
|
const selectRow = {
|
||||||
mode: 'checkbox',
|
mode: 'checkbox',
|
||||||
clickToSelect: true,
|
clickToSelect: true,
|
||||||
onSelect: (row, isSelect, rowIndex) => {
|
onSelect: (row, isSelect, rowIndex, e) => {
|
||||||
console.log(row.id);
|
console.log(row.id);
|
||||||
console.log(isSelect);
|
console.log(isSelect);
|
||||||
console.log(rowIndex);
|
console.log(rowIndex);
|
||||||
|
console.log(e);
|
||||||
},
|
},
|
||||||
onSelectAll: (isSelect, rows) => {
|
onSelectAll: (isSelect, rows, e) => {
|
||||||
console.log(isSelect);
|
console.log(isSelect);
|
||||||
console.log(rows);
|
console.log(rows);
|
||||||
|
console.log(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,7 +51,18 @@ const columns = [{
|
|||||||
|
|
||||||
const selectRow = {
|
const selectRow = {
|
||||||
mode: 'checkbox',
|
mode: 'checkbox',
|
||||||
clickToSelect: true
|
clickToSelect: true,
|
||||||
|
onSelect: (row, isSelect, rowIndex, e) => {
|
||||||
|
console.log(row.id);
|
||||||
|
console.log(isSelect);
|
||||||
|
console.log(rowIndex);
|
||||||
|
console.log(e);
|
||||||
|
},
|
||||||
|
onSelectAll: (isSelect, rows, e) => {
|
||||||
|
console.log(isSelect);
|
||||||
|
console.log(rows);
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
<BootstrapTable
|
<BootstrapTable
|
||||||
|
|||||||
144
packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js
vendored
Normal file
144
packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js
vendored
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
class SelectionManagment extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { selected: [0, 1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBtnClick = () => {
|
||||||
|
if (!this.state.selected.includes(2)) {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: [...this.state.selected, 2]
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: this.state.selected.filter(x => x !== 2)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnSelect = (row, isSelect) => {
|
||||||
|
if (isSelect) {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: [...this.state.selected, row.id]
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: this.state.selected.filter(x => x !== row.id)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnSelectAll = (isSelect, rows) => {
|
||||||
|
const ids = rows.map(r => r.id);
|
||||||
|
if (isSelect) {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: ids
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: []
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true,
|
||||||
|
selected: this.state.selected,
|
||||||
|
onSelect: this.handleOnSelect,
|
||||||
|
onSelectAll: this.handleOnSelectAll
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-success" onClick={ this.handleBtnClick }>Select/UnSelect 3rd row</button>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default class SelectionManagment extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { selected: [0, 1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBtnClick = () => {
|
||||||
|
if (!this.state.selected.includes(2)) {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: [...this.state.selected, 2]
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: this.state.selected.filter(x => x !== 2)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnSelect = (row, isSelect) => {
|
||||||
|
if (isSelect) {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: [...this.state.selected, row.id]
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: this.state.selected.filter(x => x !== row.id)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnSelectAll = (isSelect, rows) => {
|
||||||
|
const ids = rows.map(r => r.id);
|
||||||
|
if (isSelect) {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: ids
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.setState(() => ({
|
||||||
|
selected: []
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true,
|
||||||
|
selected: this.state.selected,
|
||||||
|
onSelect: this.handleOnSelect,
|
||||||
|
onSelectAll: this.handleOnSelectAll
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-success" onClick={ this.handleBtnClick }>Select/UnSelect 3rd row</button>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
62
packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js
vendored
Normal file
62
packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/* eslint no-unused-vars: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const selectRow1 = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceCode1 = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const selectRow = {
|
||||||
|
mode: 'checkbox',
|
||||||
|
clickToSelect: true
|
||||||
|
};
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField='id'
|
||||||
|
data={ [] }
|
||||||
|
columns={ columns }
|
||||||
|
selectRow={ selectRow }
|
||||||
|
noDataIndication={ 'no results found' }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ [] }
|
||||||
|
columns={ columns }
|
||||||
|
selectRow={ selectRow1 }
|
||||||
|
noDataIndication={ 'no results found' }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode1 }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -20,8 +20,8 @@ const columns = [{
|
|||||||
}];
|
}];
|
||||||
|
|
||||||
const rowEvents = {
|
const rowEvents = {
|
||||||
onClick: (e) => {
|
onClick: (e, row, rowIndex) => {
|
||||||
alert('click on row');
|
alert(`clicked on row with index: ${rowIndex}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,8 +40,8 @@ const columns = [{
|
|||||||
}];
|
}];
|
||||||
|
|
||||||
const rowEvents = {
|
const rowEvents = {
|
||||||
onClick: (e) => {
|
onClick: (e, row, rowIndex) => {
|
||||||
alert('click on row');
|
alert(\`clicked on row with index: \${rowIndex}\`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
67
packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js
vendored
Normal file
67
packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 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',
|
||||||
|
sort: true
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
sort: true
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
sort: true
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID',
|
||||||
|
sort: true
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
sort: true
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
sort: true
|
||||||
|
}];
|
||||||
|
|
||||||
|
const defaultSorted = [{
|
||||||
|
dataField: 'name',
|
||||||
|
order: 'desc'
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
defaultSortDirection="asc"
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultSortDirectionTable extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } defaultSortDirection="asc" />
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DefaultSortDirectionTable;
|
||||||
@@ -38,9 +38,28 @@ const columns = [{
|
|||||||
<BootstrapTable keyField='id' data={ products } columns={ columns } />
|
<BootstrapTable keyField='id' data={ products } columns={ columns } />
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default () => (
|
export default class Test extends React.Component {
|
||||||
<div>
|
constructor(props) {
|
||||||
<BootstrapTable keyField="id" data={ products } columns={ columns } />
|
super(props);
|
||||||
<Code>{ sourceCode }</Code>
|
this.state = { data: products };
|
||||||
</div>
|
}
|
||||||
);
|
|
||||||
|
handleClick = () => {
|
||||||
|
this.setState(() => {
|
||||||
|
const newProducts = productsGenerator(21);
|
||||||
|
return {
|
||||||
|
data: newProducts
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button className="btn btn-default" onClick={ this.handleClick }>Change Data</button>
|
||||||
|
<BootstrapTable keyField="id" data={ this.state.data } columns={ columns } />
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
58
packages/react-bootstrap-table2-example/examples/sort/sort-events.js
vendored
Normal file
58
packages/react-bootstrap-table2-example/examples/sort/sort-events.js
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* eslint no-console: 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',
|
||||||
|
sort: true
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
sort: true,
|
||||||
|
onSort: (field, order) => {
|
||||||
|
console.log(`Sort Field: ${field}, Sort Order: ${order}`);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const defaultSorted = [{
|
||||||
|
dataField: 'name',
|
||||||
|
order: 'desc'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID',
|
||||||
|
sort: true
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name',
|
||||||
|
sort: true,
|
||||||
|
onSort: (field, order) => {
|
||||||
|
console.log(....);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } />
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<BootstrapTable keyField="id" data={ products } columns={ columns } defaultSorted={ defaultSorted } />
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-example",
|
"name": "react-bootstrap-table2-example",
|
||||||
"version": "0.1.1",
|
"version": "0.1.10",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint no-mixed-operators: 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* products generator for stories
|
* products generator for stories
|
||||||
*
|
*
|
||||||
@@ -20,12 +22,41 @@ export const productsGenerator = (quantity = 5, callback) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const productsQualityGenerator = (quantity = 5) =>
|
||||||
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
|
id: index,
|
||||||
|
name: `Item name ${index}`,
|
||||||
|
quality: index % 3
|
||||||
|
}));
|
||||||
|
|
||||||
|
const jobType = ['A', 'B', 'C', 'D', 'E'];
|
||||||
|
|
||||||
|
const jobOwner = ['Allen', 'Bob', 'Cindy'];
|
||||||
|
|
||||||
export const jobsGenerator = (quantity = 5) =>
|
export const jobsGenerator = (quantity = 5) =>
|
||||||
Array.from({ length: quantity }, (value, index) => ({
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
id: index,
|
id: index,
|
||||||
name: `Job name ${index}`,
|
name: `Job name ${index}`,
|
||||||
owner: Math.floor(Math.random() * 3),
|
owner: jobOwner[Math.floor((Math.random() * 2) + 1)],
|
||||||
type: Math.floor(Math.random() * 5)
|
type: jobType[Math.floor((Math.random() * 4) + 1)]
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const todosGenerator = (quantity = 5) =>
|
||||||
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
|
id: index,
|
||||||
|
todo: `Todo item ${index}`,
|
||||||
|
done: Math.random() > 0.4 ? 'Y' : 'N'
|
||||||
|
}));
|
||||||
|
|
||||||
|
const startDate = new Date(2017, 0, 1);
|
||||||
|
const endDate = new Date();
|
||||||
|
|
||||||
|
export const stockGenerator = (quantity = 5) =>
|
||||||
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
|
id: index,
|
||||||
|
name: `Todo item ${index}`,
|
||||||
|
inStockDate:
|
||||||
|
new Date(startDate.getTime() + Math.random() * (endDate.getTime() - startDate.getTime()))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import BasicTable from 'examples/basic';
|
|||||||
import BorderlessTable from 'examples/basic/borderless-table';
|
import BorderlessTable from 'examples/basic/borderless-table';
|
||||||
import StripHoverCondensedTable from 'examples/basic/striped-hover-condensed-table';
|
import StripHoverCondensedTable from 'examples/basic/striped-hover-condensed-table';
|
||||||
import NoDataTable from 'examples/basic/no-data-table';
|
import NoDataTable from 'examples/basic/no-data-table';
|
||||||
|
import CustomizedIdClassesTable from 'examples/basic/customized-id-classes';
|
||||||
import CaptionTable from 'examples/basic/caption-table';
|
import CaptionTable from 'examples/basic/caption-table';
|
||||||
|
|
||||||
// work on columns
|
// work on columns
|
||||||
@@ -37,8 +38,25 @@ import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
|
|||||||
import TextFilter from 'examples/column-filter/text-filter';
|
import TextFilter from 'examples/column-filter/text-filter';
|
||||||
import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-default-value';
|
import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-default-value';
|
||||||
import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator';
|
import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator';
|
||||||
|
import TextFilterCaseSensitive from 'examples/column-filter/text-filter-caseSensitive';
|
||||||
import CustomTextFilter from 'examples/column-filter/custom-text-filter';
|
import CustomTextFilter from 'examples/column-filter/custom-text-filter';
|
||||||
import CustomFilterValue from 'examples/column-filter/custom-filter-value';
|
import CustomFilterValue from 'examples/column-filter/custom-filter-value';
|
||||||
|
import SelectFilter from 'examples/column-filter/select-filter';
|
||||||
|
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
|
||||||
|
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
|
||||||
|
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
|
||||||
|
import NumberFilter from 'examples/column-filter/number-filter';
|
||||||
|
import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value';
|
||||||
|
import CustomNumberFilter from 'examples/column-filter/custom-number-filter';
|
||||||
|
import 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 ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter';
|
||||||
|
import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter';
|
||||||
|
import ProgrammaticallyDateFilter from 'examples/column-filter/programmatically-date-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';
|
||||||
@@ -48,6 +66,8 @@ import RowEventTable from 'examples/rows/row-event';
|
|||||||
// table sort
|
// table sort
|
||||||
import EnableSortTable from 'examples/sort/enable-sort-table';
|
import EnableSortTable from 'examples/sort/enable-sort-table';
|
||||||
import DefaultSortTable from 'examples/sort/default-sort-table';
|
import DefaultSortTable from 'examples/sort/default-sort-table';
|
||||||
|
import DefaultSortDirectionTable from 'examples/sort/default-sort-direction';
|
||||||
|
import SortEvents from 'examples/sort/sort-events';
|
||||||
import CustomSortTable from 'examples/sort/custom-sort-table';
|
import CustomSortTable from 'examples/sort/custom-sort-table';
|
||||||
import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes';
|
import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes';
|
||||||
import HeaderSortingStyleTable from 'examples/sort/header-sorting-style';
|
import HeaderSortingStyleTable from 'examples/sort/header-sorting-style';
|
||||||
@@ -63,14 +83,25 @@ import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
|
|||||||
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
|
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
|
||||||
import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table';
|
import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table';
|
||||||
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
|
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
|
||||||
|
import EditorStyleTable from 'examples/cell-edit/editor-style-table';
|
||||||
|
import EditorClassTable from 'examples/cell-edit/editor-class-table';
|
||||||
|
import DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table';
|
||||||
|
import TextareaEditorTable from 'examples/cell-edit/textarea-editor-table';
|
||||||
|
import CheckboxEditorTable from 'examples/cell-edit/checkbox-editor-table';
|
||||||
|
import DateEditorTable from 'examples/cell-edit/date-editor-table';
|
||||||
|
import CustomEditorTable from 'examples/cell-edit/custom-editor-table';
|
||||||
|
|
||||||
// work on row selection
|
// work on row selection
|
||||||
import SingleSelectionTable from 'examples/row-selection/single-selection';
|
import SingleSelectionTable from 'examples/row-selection/single-selection';
|
||||||
import MultipleSelectionTable from 'examples/row-selection/multiple-selection';
|
import MultipleSelectionTable from 'examples/row-selection/multiple-selection';
|
||||||
import ClickToSelectTable from 'examples/row-selection/click-to-select';
|
import ClickToSelectTable from 'examples/row-selection/click-to-select';
|
||||||
|
import DefaultSelectTable from 'examples/row-selection/default-select';
|
||||||
|
import SelectionManagement from 'examples/row-selection/selection-management';
|
||||||
import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit';
|
import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit';
|
||||||
|
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';
|
||||||
@@ -98,6 +129,7 @@ import 'stories/stylesheet/tomorrow.min.css';
|
|||||||
import 'stories/stylesheet/storybook.scss';
|
import 'stories/stylesheet/storybook.scss';
|
||||||
import '../../react-bootstrap-table2/style/react-bootstrap-table2.scss';
|
import '../../react-bootstrap-table2/style/react-bootstrap-table2.scss';
|
||||||
import '../../react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss';
|
import '../../react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss';
|
||||||
|
import '../../react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss';
|
||||||
|
|
||||||
// import { action } from '@storybook/addon-actions';
|
// import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
@@ -110,6 +142,7 @@ storiesOf('Basic Table', module)
|
|||||||
.add('striped, hover, condensed table', () => <StripHoverCondensedTable />)
|
.add('striped, hover, condensed table', () => <StripHoverCondensedTable />)
|
||||||
.add('borderless table', () => <BorderlessTable />)
|
.add('borderless table', () => <BorderlessTable />)
|
||||||
.add('Indication For Empty Table', () => <NoDataTable />)
|
.add('Indication For Empty Table', () => <NoDataTable />)
|
||||||
|
.add('Customized id and class table', () => <CustomizedIdClassesTable />)
|
||||||
.add('Table with caption', () => <CaptionTable />);
|
.add('Table with caption', () => <CaptionTable />);
|
||||||
|
|
||||||
storiesOf('Work on Columns', module)
|
storiesOf('Work on Columns', module)
|
||||||
@@ -138,9 +171,26 @@ storiesOf('Column Filter', module)
|
|||||||
.add('Text Filter', () => <TextFilter />)
|
.add('Text Filter', () => <TextFilter />)
|
||||||
.add('Text Filter with Default Value', () => <TextFilterWithDefaultValue />)
|
.add('Text Filter with Default Value', () => <TextFilterWithDefaultValue />)
|
||||||
.add('Text Filter with Comparator', () => <TextFilterComparator />)
|
.add('Text Filter with Comparator', () => <TextFilterComparator />)
|
||||||
.add('Custom Text Filter', () => <CustomTextFilter />)
|
.add('Text Filter with Case Sensitive', () => <TextFilterCaseSensitive />)
|
||||||
// add another filter type example right here.
|
// add another filter type example right here.
|
||||||
.add('Custom Filter Value', () => <CustomFilterValue />);
|
.add('Select Filter', () => <SelectFilter />)
|
||||||
|
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
|
||||||
|
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
|
||||||
|
.add('Number Filter', () => <NumberFilter />)
|
||||||
|
.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 Select Filter', () => <CustomSelectFilter />)
|
||||||
|
.add('Custom Number Filter', () => <CustomNumberFilter />)
|
||||||
|
.add('Custom Date Filter', () => <CustomDateFilter />)
|
||||||
|
.add('Custom Filter Value', () => <CustomFilterValue />)
|
||||||
|
.add('Programmatically Text Filter', () => <ProgrammaticallyTextFilter />)
|
||||||
|
.add('Programmatically Select Filter', () => <ProgrammaticallySelectFilter />)
|
||||||
|
.add('Programmatically Number Filter', () => <ProgrammaticallyNumberFilter />)
|
||||||
|
.add('Programmatically Date Filter', () => <ProgrammaticallyDateFilter />)
|
||||||
|
.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 />)
|
||||||
@@ -150,6 +200,8 @@ storiesOf('Work on Rows', module)
|
|||||||
storiesOf('Sort Table', module)
|
storiesOf('Sort Table', module)
|
||||||
.add('Enable Sort', () => <EnableSortTable />)
|
.add('Enable Sort', () => <EnableSortTable />)
|
||||||
.add('Default Sort Table', () => <DefaultSortTable />)
|
.add('Default Sort Table', () => <DefaultSortTable />)
|
||||||
|
.add('Default Sort Direction Table', () => <DefaultSortDirectionTable />)
|
||||||
|
.add('Sort Events', () => <SortEvents />)
|
||||||
.add('Custom Sort Fuction', () => <CustomSortTable />)
|
.add('Custom Sort Fuction', () => <CustomSortTable />)
|
||||||
.add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />)
|
.add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />)
|
||||||
.add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />);
|
.add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />);
|
||||||
@@ -163,16 +215,27 @@ storiesOf('Cell Editing', module)
|
|||||||
.add('Cell Level Editable', () => <CellLevelEditable />)
|
.add('Cell Level Editable', () => <CellLevelEditable />)
|
||||||
.add('Rich Hook Functions', () => <CellEditHooks />)
|
.add('Rich Hook Functions', () => <CellEditHooks />)
|
||||||
.add('Validation', () => <CellEditValidator />)
|
.add('Validation', () => <CellEditValidator />)
|
||||||
.add('Custom Cell Style When Editing', () => <CellEditStyleTable />)
|
.add('Custom Cell Style', () => <CellEditStyleTable />)
|
||||||
.add('Custom Cell Classes When Editing', () => <CellEditClassTable />);
|
.add('Custom Cell Classes', () => <CellEditClassTable />)
|
||||||
|
.add('Custom Editor Classes', () => <EditorClassTable />)
|
||||||
|
.add('Custom Editor Style', () => <EditorStyleTable />)
|
||||||
|
.add('Dropdown Editor', () => <DropdownEditorTable />)
|
||||||
|
.add('Textarea Editor', () => <TextareaEditorTable />)
|
||||||
|
.add('Checkbox Editor', () => <CheckboxEditorTable />)
|
||||||
|
.add('Date Editor', () => <DateEditorTable />)
|
||||||
|
.add('Custom Editor', () => <CustomEditorTable />);
|
||||||
|
|
||||||
storiesOf('Row Selection', module)
|
storiesOf('Row Selection', module)
|
||||||
.add('Single Selection', () => <SingleSelectionTable />)
|
.add('Single Selection', () => <SingleSelectionTable />)
|
||||||
.add('Multiple Selection', () => <MultipleSelectionTable />)
|
.add('Multiple Selection', () => <MultipleSelectionTable />)
|
||||||
.add('Click to Select', () => <ClickToSelectTable />)
|
.add('Click to Select', () => <ClickToSelectTable />)
|
||||||
|
.add('Default Select', () => <DefaultSelectTable />)
|
||||||
|
.add('Selection Management', () => <SelectionManagement />)
|
||||||
.add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />)
|
.add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />)
|
||||||
|
.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 />)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
table.foo {
|
||||||
|
background-color: $grey-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
table#bar {
|
||||||
|
background-color: $light-blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.boo {
|
||||||
|
border: 2px solid salmon;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
@import "base/github-corner";
|
@import "base/github-corner";
|
||||||
@import "base/code-block";
|
@import "base/code-block";
|
||||||
|
|
||||||
|
@import "base-table/index";
|
||||||
@import "welcome/index";
|
@import "welcome/index";
|
||||||
@import "columns/index";
|
@import "columns/index";
|
||||||
@import "cell-edit/index";
|
@import "cell-edit/index";
|
||||||
|
|||||||
@@ -17,8 +17,22 @@ $ npm install react-bootstrap-table2-filter --save
|
|||||||
You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters:
|
You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters:
|
||||||
|
|
||||||
* TextFilter
|
* TextFilter
|
||||||
|
* SelectFilter
|
||||||
|
* NumberFilter
|
||||||
|
* DateFilter
|
||||||
|
* CustomFilter
|
||||||
* **Coming soon!**
|
* **Coming soon!**
|
||||||
|
|
||||||
|
## Add CSS
|
||||||
|
|
||||||
|
```js
|
||||||
|
// es5
|
||||||
|
require('react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css');
|
||||||
|
|
||||||
|
// es6
|
||||||
|
import 'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css';
|
||||||
|
```
|
||||||
|
|
||||||
## Text Filter
|
## Text Filter
|
||||||
Following is a quick demo for enable the column filter on **Product Price** column!!
|
Following is a quick demo for enable the column filter on **Product Price** column!!
|
||||||
|
|
||||||
@@ -47,9 +61,183 @@ const priceFilter = textFilter({
|
|||||||
className: 'my-custom-text-filter', // custom classname on input
|
className: 'my-custom-text-filter', // custom classname on input
|
||||||
defaultValue: 'test', // default filtering value
|
defaultValue: 'test', // default filtering value
|
||||||
comparator: Comparator.EQ, // default is Comparator.LIKE
|
comparator: Comparator.EQ, // default is Comparator.LIKE
|
||||||
|
caseSensitive: true, // default is false, and true will only work when comparator is LIKE
|
||||||
style: { ... }, // your custom styles on input
|
style: { ... }, // your custom styles on input
|
||||||
delay: 1000 // how long will trigger filtering after user typing, default is 500 ms
|
delay: 1000 // how long will trigger filtering after user typing, default is 500 ms
|
||||||
});
|
});
|
||||||
|
|
||||||
// omit...
|
// omit...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Select Filter
|
||||||
|
A quick example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { selectFilter } 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: selectFilter({
|
||||||
|
options: selectOptions
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
```
|
||||||
|
|
||||||
|
Following is an example for custom select filter:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
// omit...
|
||||||
|
|
||||||
|
const qualityFilter = selectFilter({
|
||||||
|
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
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
|
||||||
|
|
||||||
|
const columns = [..., {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price',
|
||||||
|
filter: numberFilter()
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||||
|
```
|
||||||
|
|
||||||
|
Numner filter is same as other filter, you can custom the number filter via `numberFilter` factory function:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
|
||||||
|
// omit...
|
||||||
|
|
||||||
|
const numberFilter = numberFilter({
|
||||||
|
options: [2100, 2103, 2105], // if options defined, will render number select instead of number input
|
||||||
|
delay: 600, // how long will trigger filtering after user typing, default is 500 ms
|
||||||
|
placeholder: 'custom placeholder', // placeholder for number input
|
||||||
|
withoutEmptyComparatorOption: true, // dont render empty option for comparator
|
||||||
|
withoutEmptyNumberOption: true, // dont render empty option for numner select if it is defined
|
||||||
|
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators
|
||||||
|
style: { display: 'inline-grid' }, // custom the style on number filter
|
||||||
|
className: 'custom-numberfilter-class', // custom the class on number filter
|
||||||
|
comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select
|
||||||
|
comparatorClassName: 'custom-comparator-class', // custom the class on comparator select
|
||||||
|
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on number input/select
|
||||||
|
numberClassName: 'custom-number-class', // custom the class on ber input/select
|
||||||
|
defaultValue: { number: 2103, comparator: Comparator.GT } // default value
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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
|
||||||
25
packages/react-bootstrap-table2-filter/index.js
vendored
25
packages/react-bootstrap-table2-filter/index.js
vendored
@@ -1,15 +1,40 @@
|
|||||||
import TextFilter from './src/components/text';
|
import TextFilter from './src/components/text';
|
||||||
|
import SelectFilter from './src/components/select';
|
||||||
|
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 = {}) => ({
|
||||||
Filter: TextFilter,
|
Filter: TextFilter,
|
||||||
props
|
props
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const selectFilter = (props = {}) => ({
|
||||||
|
Filter: SelectFilter,
|
||||||
|
props
|
||||||
|
});
|
||||||
|
|
||||||
|
export const numberFilter = (props = {}) => ({
|
||||||
|
Filter: NumberFilter,
|
||||||
|
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.1",
|
"version": "0.3.0",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
export const LIKE = 'LIKE';
|
export const LIKE = 'LIKE';
|
||||||
export const EQ = '=';
|
export const EQ = '=';
|
||||||
|
export const NE = '!=';
|
||||||
|
export const GT = '>';
|
||||||
|
export const GE = '>=';
|
||||||
|
export const LT = '<';
|
||||||
|
export const LE = '<=';
|
||||||
|
|||||||
209
packages/react-bootstrap-table2-filter/src/components/date.js
vendored
Normal file
209
packages/react-bootstrap-table2-filter/src/components/date.js
vendored
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/* 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 = () => {
|
||||||
|
const date = typeof value !== 'object' ? new Date(value) : 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;
|
||||||
270
packages/react-bootstrap-table2-filter/src/components/number.js
vendored
Normal file
270
packages/react-bootstrap-table2-filter/src/components/number.js
vendored
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
/* eslint jsx-a11y/no-static-element-interactions: 0 */
|
||||||
|
/* eslint react/require-default-props: 0 */
|
||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import * as Comparator from '../comparison';
|
||||||
|
import { FILTER_TYPE, FILTER_DELAY } from '../const';
|
||||||
|
|
||||||
|
const legalComparators = [
|
||||||
|
Comparator.EQ,
|
||||||
|
Comparator.NE,
|
||||||
|
Comparator.GT,
|
||||||
|
Comparator.GE,
|
||||||
|
Comparator.LT,
|
||||||
|
Comparator.LE
|
||||||
|
];
|
||||||
|
|
||||||
|
class NumberFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.comparators = props.comparators || legalComparators;
|
||||||
|
this.timeout = null;
|
||||||
|
let isSelected = props.defaultValue !== undefined && props.defaultValue.number !== undefined;
|
||||||
|
if (props.options && isSelected) {
|
||||||
|
isSelected = props.options.indexOf(props.defaultValue.number) > -1;
|
||||||
|
}
|
||||||
|
this.state = { isSelected };
|
||||||
|
this.onChangeNumber = this.onChangeNumber.bind(this);
|
||||||
|
this.onChangeNumberSet = this.onChangeNumberSet.bind(this);
|
||||||
|
this.onChangeComparator = this.onChangeComparator.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { column, onFilter, getFilter } = this.props;
|
||||||
|
const comparator = this.numberFilterComparator.value;
|
||||||
|
const number = this.numberFilter.value;
|
||||||
|
if (comparator && number) {
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator });
|
||||||
|
}
|
||||||
|
|
||||||
|
// export onFilter function to allow users to access
|
||||||
|
if (getFilter) {
|
||||||
|
getFilter((filterVal) => {
|
||||||
|
this.setState(() => ({ isSelected: (filterVal !== '') }));
|
||||||
|
this.numberFilterComparator.value = filterVal.comparator;
|
||||||
|
this.numberFilter.value = filterVal.number;
|
||||||
|
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({
|
||||||
|
number: filterVal.number,
|
||||||
|
comparator: filterVal.comparator
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeNumber(e) {
|
||||||
|
const { delay, column, onFilter } = this.props;
|
||||||
|
const comparator = this.numberFilterComparator.value;
|
||||||
|
if (comparator === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
const filterValue = e.target.value;
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({ number: filterValue, comparator });
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeNumberSet(e) {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const comparator = this.numberFilterComparator.value;
|
||||||
|
const { value } = e.target;
|
||||||
|
this.setState(() => ({ isSelected: (value !== '') }));
|
||||||
|
// if (comparator === '') {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator });
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeComparator(e) {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const value = this.numberFilter.value;
|
||||||
|
const comparator = e.target.value;
|
||||||
|
// if (value === '') {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({ number: 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
getNumberOptions() {
|
||||||
|
const optionTags = [];
|
||||||
|
const { options, column, withoutEmptyNumberOption } = this.props;
|
||||||
|
if (!withoutEmptyNumberOption) {
|
||||||
|
optionTags.push(
|
||||||
|
<option key="-1" value="">
|
||||||
|
{ this.props.placeholder || `Select ${column.text}...` }
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < options.length; i += 1) {
|
||||||
|
optionTags.push(<option key={ i } value={ options[i] }>{ options[i] }</option>);
|
||||||
|
}
|
||||||
|
return optionTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(filterObj) {
|
||||||
|
const { column, onFilter } = this.props;
|
||||||
|
const { number, comparator } = filterObj;
|
||||||
|
this.setState(() => ({ isSelected: (number !== '') }));
|
||||||
|
this.numberFilterComparator.value = comparator;
|
||||||
|
this.numberFilter.value = number;
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator });
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanFiltered() {
|
||||||
|
const { column, onFilter, defaultValue } = this.props;
|
||||||
|
const value = defaultValue ? defaultValue.number : '';
|
||||||
|
const comparator = defaultValue ? defaultValue.comparator : '';
|
||||||
|
this.setState(() => ({ isSelected: (value !== '') }));
|
||||||
|
this.numberFilterComparator.value = comparator;
|
||||||
|
this.numberFilter.value = value;
|
||||||
|
onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isSelected } = this.state;
|
||||||
|
const {
|
||||||
|
defaultValue,
|
||||||
|
column,
|
||||||
|
options,
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
numberStyle,
|
||||||
|
numberClassName,
|
||||||
|
comparatorStyle,
|
||||||
|
comparatorClassName,
|
||||||
|
placeholder
|
||||||
|
} = this.props;
|
||||||
|
const selectClass = `
|
||||||
|
select-filter
|
||||||
|
number-filter-input
|
||||||
|
form-control
|
||||||
|
${numberClassName}
|
||||||
|
${!isSelected ? 'placeholder-selected' : ''}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
|
className={ `filter number-filter ${className}` }
|
||||||
|
style={ style }
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
ref={ n => this.numberFilterComparator = n }
|
||||||
|
style={ comparatorStyle }
|
||||||
|
className={ `number-filter-comparator form-control ${comparatorClassName}` }
|
||||||
|
onChange={ this.onChangeComparator }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.comparator : '' }
|
||||||
|
>
|
||||||
|
{ this.getComparatorOptions() }
|
||||||
|
</select>
|
||||||
|
{
|
||||||
|
options ?
|
||||||
|
<select
|
||||||
|
ref={ n => this.numberFilter = n }
|
||||||
|
style={ numberStyle }
|
||||||
|
className={ selectClass }
|
||||||
|
onChange={ this.onChangeNumberSet }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.number : '' }
|
||||||
|
>
|
||||||
|
{ this.getNumberOptions() }
|
||||||
|
</select> :
|
||||||
|
<input
|
||||||
|
ref={ n => this.numberFilter = n }
|
||||||
|
type="number"
|
||||||
|
style={ numberStyle }
|
||||||
|
className={ `number-filter-input form-control ${numberClassName}` }
|
||||||
|
placeholder={ placeholder || `Enter ${column.text}...` }
|
||||||
|
onChange={ this.onChangeNumber }
|
||||||
|
defaultValue={ defaultValue ? defaultValue.number : '' }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberFilter.propTypes = {
|
||||||
|
onFilter: PropTypes.func.isRequired,
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
options: PropTypes.arrayOf(PropTypes.number),
|
||||||
|
defaultValue: PropTypes.shape({
|
||||||
|
number: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
comparator: PropTypes.oneOf([...legalComparators, ''])
|
||||||
|
}),
|
||||||
|
delay: PropTypes.number,
|
||||||
|
/* 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(`Number comparator provided is not supported.
|
||||||
|
Use only ${legalComparators}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
withoutEmptyComparatorOption: PropTypes.bool,
|
||||||
|
withoutEmptyNumberOption: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
className: PropTypes.string,
|
||||||
|
comparatorStyle: PropTypes.object,
|
||||||
|
comparatorClassName: PropTypes.string,
|
||||||
|
numberStyle: PropTypes.object,
|
||||||
|
numberClassName: PropTypes.string,
|
||||||
|
getFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberFilter.defaultProps = {
|
||||||
|
delay: FILTER_DELAY,
|
||||||
|
options: undefined,
|
||||||
|
defaultValue: {
|
||||||
|
number: undefined,
|
||||||
|
comparator: ''
|
||||||
|
},
|
||||||
|
withoutEmptyComparatorOption: false,
|
||||||
|
withoutEmptyNumberOption: false,
|
||||||
|
comparators: legalComparators,
|
||||||
|
placeholder: undefined,
|
||||||
|
style: undefined,
|
||||||
|
className: '',
|
||||||
|
comparatorStyle: undefined,
|
||||||
|
comparatorClassName: '',
|
||||||
|
numberStyle: undefined,
|
||||||
|
numberClassName: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NumberFilter;
|
||||||
150
packages/react-bootstrap-table2-filter/src/components/select.js
vendored
Normal file
150
packages/react-bootstrap-table2-filter/src/components/select.js
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/* eslint react/require-default-props: 0 */
|
||||||
|
/* eslint no-return-assign: 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.filter = this.filter.bind(this);
|
||||||
|
const isSelected = props.options[props.defaultValue] !== undefined;
|
||||||
|
this.state = { isSelected };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { column, onFilter, getFilter } = this.props;
|
||||||
|
|
||||||
|
const value = this.selectInput.value;
|
||||||
|
if (value && value !== '') {
|
||||||
|
onFilter(column, FILTER_TYPE.SELECT)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export onFilter function to allow users to access
|
||||||
|
if (getFilter) {
|
||||||
|
getFilter((filterVal) => {
|
||||||
|
this.setState(() => ({ isSelected: filterVal !== '' }));
|
||||||
|
this.selectInput.value = filterVal;
|
||||||
|
|
||||||
|
onFilter(column, FILTER_TYPE.SELECT)(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) {
|
||||||
|
const value = this.selectInput.value;
|
||||||
|
if (value) {
|
||||||
|
this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(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.setState(() => ({ isSelected: value !== '' }));
|
||||||
|
this.selectInput.value = value;
|
||||||
|
this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(value) {
|
||||||
|
this.selectInput.value = value;
|
||||||
|
this.setState(() => ({ isSelected: value !== '' }));
|
||||||
|
this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(e) {
|
||||||
|
const { value } = e.target;
|
||||||
|
this.setState(() => ({ isSelected: value !== '' }));
|
||||||
|
this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(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 }
|
||||||
|
className={ selectClass }
|
||||||
|
onChange={ this.filter }
|
||||||
|
onClick={ e => e.stopPropagation() }
|
||||||
|
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
|
||||||
|
>
|
||||||
|
{ this.getOptions() }
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectFilter.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.any,
|
||||||
|
caseSensitive: PropTypes.bool,
|
||||||
|
getFilter: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectFilter.defaultProps = {
|
||||||
|
defaultValue: '',
|
||||||
|
className: '',
|
||||||
|
withoutEmptyOption: false,
|
||||||
|
comparator: EQ,
|
||||||
|
caseSensitive: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectFilter;
|
||||||
@@ -17,10 +17,21 @@ class TextFilter extends Component {
|
|||||||
value: props.defaultValue
|
value: props.defaultValue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const { onFilter, getFilter, column } = this.props;
|
||||||
const defaultValue = this.input.value;
|
const defaultValue = this.input.value;
|
||||||
|
|
||||||
if (defaultValue) {
|
if (defaultValue) {
|
||||||
this.props.onFilter(this.props.column, defaultValue, FILTER_TYPE.TEXT);
|
onFilter(this.props.column, FILTER_TYPE.TEXT)(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export onFilter function to allow users to access
|
||||||
|
if (getFilter) {
|
||||||
|
getFilter((filterVal) => {
|
||||||
|
this.setState(() => ({ value: filterVal }));
|
||||||
|
onFilter(column, FILTER_TYPE.TEXT)(filterVal);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +51,7 @@ class TextFilter extends Component {
|
|||||||
const filterValue = e.target.value;
|
const filterValue = e.target.value;
|
||||||
this.setState(() => ({ value: filterValue }));
|
this.setState(() => ({ value: filterValue }));
|
||||||
this.timeout = setTimeout(() => {
|
this.timeout = setTimeout(() => {
|
||||||
this.props.onFilter(this.props.column, filterValue, FILTER_TYPE.TEXT);
|
this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(filterValue);
|
||||||
}, this.props.delay);
|
}, this.props.delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,12 +64,12 @@ class TextFilter extends Component {
|
|||||||
cleanFiltered() {
|
cleanFiltered() {
|
||||||
const value = this.props.defaultValue;
|
const value = this.props.defaultValue;
|
||||||
this.setState(() => ({ value }));
|
this.setState(() => ({ value }));
|
||||||
this.props.onFilter(this.props.column, value, FILTER_TYPE.TEXT);
|
this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilter(filterText) {
|
applyFilter(filterText) {
|
||||||
this.setState(() => ({ value: filterText }));
|
this.setState(() => ({ value: filterText }));
|
||||||
this.props.onFilter(this.props.column, filterText, FILTER_TYPE.TEXT);
|
this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(filterText);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick(e) {
|
handleClick(e) {
|
||||||
@@ -69,7 +80,18 @@ class TextFilter extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { placeholder, column: { text }, style, className, onFilter, ...rest } = this.props;
|
const {
|
||||||
|
placeholder,
|
||||||
|
column: { text },
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
onFilter,
|
||||||
|
caseSensitive,
|
||||||
|
defaultValue,
|
||||||
|
getFilter,
|
||||||
|
...rest
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
// stopPropagation for onClick event is try to prevent sort was triggered.
|
// stopPropagation for onClick event is try to prevent sort was triggered.
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
@@ -95,12 +117,15 @@ TextFilter.propTypes = {
|
|||||||
delay: PropTypes.number,
|
delay: PropTypes.number,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
className: PropTypes.string
|
className: PropTypes.string,
|
||||||
|
caseSensitive: PropTypes.bool,
|
||||||
|
getFilter: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
TextFilter.defaultProps = {
|
TextFilter.defaultProps = {
|
||||||
delay: FILTER_DELAY,
|
delay: FILTER_DELAY,
|
||||||
defaultValue: ''
|
defaultValue: '',
|
||||||
|
caseSensitive: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
export const FILTER_TYPE = {
|
export const FILTER_TYPE = {
|
||||||
TEXT: 'TEXT'
|
TEXT: 'TEXT',
|
||||||
|
SELECT: 'SELECT',
|
||||||
|
NUMBER: 'NUMBER',
|
||||||
|
DATE: 'DATE'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FILTER_DELAY = 500;
|
export const FILTER_DELAY = 500;
|
||||||
|
|||||||
197
packages/react-bootstrap-table2-filter/src/filter.js
vendored
197
packages/react-bootstrap-table2-filter/src/filter.js
vendored
@@ -1,30 +1,205 @@
|
|||||||
|
/* eslint eqeqeq: 0 */
|
||||||
|
/* eslint no-console: 0 */
|
||||||
import { FILTER_TYPE } from './const';
|
import { FILTER_TYPE } from './const';
|
||||||
import { LIKE, EQ } from './comparison';
|
import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison';
|
||||||
|
|
||||||
export const filterByText = _ => (
|
export const filterByText = _ => (
|
||||||
data,
|
data,
|
||||||
dataField,
|
dataField,
|
||||||
{ filterVal, comparator = LIKE },
|
{ filterVal: userInput = '', comparator = LIKE, caseSensitive },
|
||||||
customFilterValue
|
customFilterValue
|
||||||
) =>
|
) => {
|
||||||
|
// make sure filter value to be a string
|
||||||
|
const filterVal = userInput.toString();
|
||||||
|
|
||||||
|
return (
|
||||||
|
data.filter((row) => {
|
||||||
|
let cell = _.get(row, dataField);
|
||||||
|
if (customFilterValue) {
|
||||||
|
cell = customFilterValue(cell, row);
|
||||||
|
}
|
||||||
|
const cellStr = _.isDefined(cell) ? cell.toString() : '';
|
||||||
|
if (comparator === EQ) {
|
||||||
|
return cellStr === filterVal;
|
||||||
|
}
|
||||||
|
if (caseSensitive) {
|
||||||
|
return cellStr.includes(filterVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cellStr.toLocaleUpperCase().indexOf(filterVal.toLocaleUpperCase()) !== -1;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filterByNumber = _ => (
|
||||||
|
data,
|
||||||
|
dataField,
|
||||||
|
{ filterVal: { comparator, number } },
|
||||||
|
customFilterValue
|
||||||
|
) => (
|
||||||
data.filter((row) => {
|
data.filter((row) => {
|
||||||
|
if (number === '' || !comparator) return true;
|
||||||
|
let valid = true;
|
||||||
let cell = _.get(row, dataField);
|
let cell = _.get(row, dataField);
|
||||||
if (customFilterValue) {
|
if (customFilterValue) {
|
||||||
cell = customFilterValue(cell, row);
|
cell = customFilterValue(cell, row);
|
||||||
}
|
}
|
||||||
const cellStr = _.isDefined(cell) ? cell.toString() : '';
|
|
||||||
if (comparator === EQ) {
|
switch (comparator) {
|
||||||
return cellStr === filterVal;
|
case EQ: {
|
||||||
|
if (cell != number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GT: {
|
||||||
|
if (cell <= number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GE: {
|
||||||
|
if (cell < number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LT: {
|
||||||
|
if (cell >= number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LE: {
|
||||||
|
if (cell > number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NE: {
|
||||||
|
if (cell == number) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.error('Number comparator provided is not supported');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cellStr.indexOf(filterVal) > -1;
|
return valid;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
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 filterFactory = _ => (filterType) => {
|
export const filterFactory = _ => (filterType) => {
|
||||||
let filterFn;
|
let filterFn;
|
||||||
switch (filterType) {
|
switch (filterType) {
|
||||||
case FILTER_TYPE.TEXT:
|
case FILTER_TYPE.TEXT:
|
||||||
|
case FILTER_TYPE.SELECT:
|
||||||
filterFn = filterByText(_);
|
filterFn = filterByText(_);
|
||||||
break;
|
break;
|
||||||
|
case FILTER_TYPE.NUMBER:
|
||||||
|
filterFn = filterByNumber(_);
|
||||||
|
break;
|
||||||
|
case FILTER_TYPE.DATE:
|
||||||
|
filterFn = filterByDate(_);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
filterFn = filterByText(_);
|
filterFn = filterByText(_);
|
||||||
}
|
}
|
||||||
@@ -38,7 +213,13 @@ export const filters = (store, columns, _) => (currFilters) => {
|
|||||||
Object.keys(currFilters).forEach((dataField) => {
|
Object.keys(currFilters).forEach((dataField) => {
|
||||||
const filterObj = currFilters[dataField];
|
const filterObj = currFilters[dataField];
|
||||||
filterFn = factory(filterObj.filterType);
|
filterFn = factory(filterObj.filterType);
|
||||||
const { filterValue } = columns.find(col => col.dataField === dataField);
|
let filterValue;
|
||||||
|
for (let i = 0; i < columns.length; i += 1) {
|
||||||
|
if (columns[i].dataField === dataField) {
|
||||||
|
filterValue = columns[i].filterValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
result = filterFn(result, dataField, filterObj, filterValue);
|
result = filterFn(result, dataField, filterObj, filterValue);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { filters } from './filter';
|
import { filters } from './filter';
|
||||||
import { LIKE } from './comparison';
|
import { LIKE, EQ } from './comparison';
|
||||||
|
import { FILTER_TYPE } from './const';
|
||||||
|
|
||||||
export default (Base, {
|
export default (Base, {
|
||||||
_,
|
_,
|
||||||
@@ -19,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 }) {
|
||||||
@@ -29,39 +31,58 @@ export default (Base, {
|
|||||||
// I think this condition only isRemoteFilter is enough
|
// I think this condition only isRemoteFilter is enough
|
||||||
store.filteredData = store.getAllData();
|
store.filteredData = store.getAllData();
|
||||||
this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
|
this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
|
||||||
} else if (isDataChanged) {
|
} else {
|
||||||
if (!isRemoteFilter && Object.keys(this.state.currFilters).length > 0) {
|
if (Object.keys(this.state.currFilters).length > 0) {
|
||||||
store.filteredData = filters(store, columns, _)(this.state.currFilters);
|
store.filteredData = filters(store, columns, _)(this.state.currFilters);
|
||||||
}
|
}
|
||||||
this.setState(() => ({ isDataChanged }));
|
this.setState(() => ({ isDataChanged }));
|
||||||
} else {
|
|
||||||
this.setState(() => ({ isDataChanged: false }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onFilter(column, filterVal, filterType) {
|
/**
|
||||||
const { store, columns } = this.props;
|
* filter the table like below:
|
||||||
const currFilters = Object.assign({}, this.state.currFilters);
|
* onFilter(column, filterType)(filterVal)
|
||||||
const { dataField, filter } = column;
|
* @param {Object} column
|
||||||
|
* @param {String} filterType
|
||||||
|
* @param {String} filterVal - user input for filtering.
|
||||||
|
*/
|
||||||
|
onFilter(column, filterType) {
|
||||||
|
return (filterVal) => {
|
||||||
|
const { store, columns } = this.props;
|
||||||
|
// watch out here if migration to context API, #334
|
||||||
|
const currFilters = Object.assign({}, store.filters);
|
||||||
|
const { dataField, filter } = column;
|
||||||
|
|
||||||
if (!_.isDefined(filterVal) || filterVal === '') {
|
if (!_.isDefined(filterVal) || filterVal === '') {
|
||||||
delete currFilters[dataField];
|
delete currFilters[dataField];
|
||||||
} else {
|
} else {
|
||||||
const { comparator = LIKE } = filter.props;
|
// select default comparator is EQ, others are LIKE
|
||||||
currFilters[dataField] = { filterVal, filterType, comparator };
|
const {
|
||||||
}
|
comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE),
|
||||||
store.filters = currFilters;
|
caseSensitive = false
|
||||||
|
} = filter.props;
|
||||||
|
currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive };
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isRemoteFiltering() || this.isRemotePagination()) {
|
store.filters = currFilters;
|
||||||
this.handleRemoteFilterChange();
|
|
||||||
// when remote filtering is enable, dont set currFilters state
|
|
||||||
// in the componentWillReceiveProps,
|
|
||||||
// it's the key point that we can know the filter is changed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
store.filteredData = filters(store, columns, _)(currFilters);
|
if (this.isRemoteFiltering() || this.isRemotePagination()) {
|
||||||
this.setState(() => ({ currFilters, isDataChanged: true }));
|
this.handleRemoteFilterChange();
|
||||||
|
// when remote filtering is enable, dont set currFilters state
|
||||||
|
// in the componentWillReceiveProps,
|
||||||
|
// it's the key point that we can know the filter is changed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
store.filteredData = filters(store, columns, _)(currFilters);
|
||||||
|
this.setState(() => ({ currFilters, isDataChanged: true }));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onExternalFilter(column, filterType) {
|
||||||
|
return (value) => {
|
||||||
|
this.onFilter(column, filterType)(value);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -70,6 +91,7 @@ export default (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 }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
.react-bootstrap-table > table > thead > tr > th .filter {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 .filter::-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;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) {
|
||||||
|
color: initial;
|
||||||
|
font-style: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter-input,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter-input {
|
||||||
|
margin-left: 5px;
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - 67px - 5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .number-filter-comparator,
|
||||||
|
.react-bootstrap-table > table > thead > tr > th .date-filter-comparator {
|
||||||
|
width: 67px;
|
||||||
|
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,348 @@
|
|||||||
|
import 'jsdom-global/register';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { mount } from 'enzyme';
|
||||||
|
import NumberFilter from '../../src/components/number';
|
||||||
|
import { FILTER_TYPE } from '../../src/const';
|
||||||
|
import * as Comparator from '../../src/comparison';
|
||||||
|
|
||||||
|
|
||||||
|
describe('Number Filter', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
// onFilter(x)(y) = filter result
|
||||||
|
const onFilter = sinon.stub();
|
||||||
|
const onFilterFirstReturn = sinon.stub();
|
||||||
|
|
||||||
|
const column = {
|
||||||
|
dataField: 'price',
|
||||||
|
text: 'Product Price'
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
onFilter.reset();
|
||||||
|
onFilterFirstReturn.reset();
|
||||||
|
|
||||||
|
onFilter.returns(onFilterFirstReturn);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initialization', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter onFilter={ onFilter } column={ column } />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct state', () => {
|
||||||
|
expect(wrapper.state().isSelected).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('select')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('input[type="number"]')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.number-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(
|
||||||
|
<NumberFilter onFilter={ onFilter } column={ column } withoutEmptyComparatorOption />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering comparator options correctly', () => {
|
||||||
|
const select = wrapper.find('select');
|
||||||
|
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.number props is defined', () => {
|
||||||
|
const number = 203;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { number } } />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering input successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
const input = wrapper.find('input[type="number"]');
|
||||||
|
expect(input).toHaveLength(1);
|
||||||
|
expect(input.props().defaultValue).toEqual(number);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.comparator props is defined', () => {
|
||||||
|
const comparator = Comparator.EQ;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { comparator } } />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering comparator select successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
const select = wrapper.find('.number-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 number = 123;
|
||||||
|
|
||||||
|
const getFilter = (filter) => {
|
||||||
|
programmaticallyFilter = filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter onFilter={ onFilter } column={ column } getFilter={ getFilter } />
|
||||||
|
);
|
||||||
|
|
||||||
|
programmaticallyFilter({ comparator, number });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do onFilter correctly when exported function was executed', () => {
|
||||||
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.NUMBER)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith({ comparator, number })).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setState correctly when exported function was executed', () => {
|
||||||
|
expect(wrapper.state().isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
|
||||||
|
const number = 203;
|
||||||
|
const comparator = Comparator.EQ;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
defaultValue={ { number, comparator } }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct state', () => {
|
||||||
|
expect(wrapper.state().isSelected).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calling onFilter on componentDidMount', () => {
|
||||||
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.NUMBER)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith({ number: `${number}`, comparator })).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when options props is defined', () => {
|
||||||
|
const options = [2100, 2103, 2105];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering number options instead of number input', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
const select = wrapper.find('.select-filter.placeholder-selected');
|
||||||
|
expect(select).toHaveLength(1);
|
||||||
|
expect(select.find('option')).toHaveLength(options.length + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when withoutEmptyNumberOption props is defined', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
withoutEmptyNumberOption
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering number options instead of number input', () => {
|
||||||
|
const select = wrapper.find('.select-filter.placeholder-selected');
|
||||||
|
expect(select).toHaveLength(1);
|
||||||
|
expect(select.find('option')).toHaveLength(options.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.number props is defined', () => {
|
||||||
|
const number = 203;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
defaultValue={ { number } }
|
||||||
|
options={ options }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering number options successfully', () => {
|
||||||
|
const select = wrapper.find('.select-filter.placeholder-selected');
|
||||||
|
expect(select).toHaveLength(1);
|
||||||
|
expect(select.props().defaultValue).toEqual(number);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
|
||||||
|
const number = options[1];
|
||||||
|
const comparator = Comparator.EQ;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
defaultValue={ { number, comparator } }
|
||||||
|
options={ options }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering number options successfully', () => {
|
||||||
|
let select = wrapper.find('.placeholder-selected');
|
||||||
|
expect(select).toHaveLength(0);
|
||||||
|
|
||||||
|
select = wrapper.find('.select-filter');
|
||||||
|
expect(select).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when style props is defined', () => {
|
||||||
|
const style = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
style={ style }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.number-filter').prop('style')).toEqual(style);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when numberStyle props is defined', () => {
|
||||||
|
const numberStyle = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
numberStyle={ numberStyle }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.number-filter-input').prop('style')).toEqual(numberStyle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when comparatorStyle props is defined', () => {
|
||||||
|
const comparatorStyle = { backgroundColor: 'red' };
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
comparatorStyle={ comparatorStyle }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('select').prop('style')).toEqual(comparatorStyle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when className props is defined', () => {
|
||||||
|
const className = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
className={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.hasClass(className)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when numberClassName props is defined', () => {
|
||||||
|
const className = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
numberClassName={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('.number-filter-input').prop('className').indexOf(className) > -1).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when comparatorClassName props is defined', () => {
|
||||||
|
const className = 'test';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<NumberFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
comparatorClassName={ className }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering component successfully', () => {
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('select').prop('className').indexOf(className) > -1).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,350 @@
|
|||||||
|
import 'jsdom-global/register';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { mount } from 'enzyme';
|
||||||
|
import SelectFilter from '../../src/components/select';
|
||||||
|
import { FILTER_TYPE } from '../../src/const';
|
||||||
|
|
||||||
|
|
||||||
|
describe('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(
|
||||||
|
<SelectFilter 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(
|
||||||
|
<SelectFilter
|
||||||
|
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.SELECT)).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(
|
||||||
|
<SelectFilter
|
||||||
|
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.SELECT)).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(
|
||||||
|
<SelectFilter
|
||||||
|
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(
|
||||||
|
<SelectFilter
|
||||||
|
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(
|
||||||
|
<SelectFilter
|
||||||
|
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', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<SelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ options }
|
||||||
|
defaultValue="0"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
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.SELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||||
|
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when props.options is diff from prevProps.options', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<SelectFilter
|
||||||
|
onFilter={ onFilter }
|
||||||
|
column={ column }
|
||||||
|
options={ {
|
||||||
|
...options,
|
||||||
|
3: 'Best'
|
||||||
|
} }
|
||||||
|
defaultValue="1"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
prevProps = {
|
||||||
|
column,
|
||||||
|
options
|
||||||
|
};
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.componentDidUpdate(prevProps);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update', () => {
|
||||||
|
expect(onFilter.callCount).toBe(2);
|
||||||
|
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).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(
|
||||||
|
<SelectFilter
|
||||||
|
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.SELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||||
|
expect(onFilterFirstReturn.calledWith(defaultValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when props.defaultValue is not defined', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<SelectFilter
|
||||||
|
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 value = '2';
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
|
||||||
|
);
|
||||||
|
instance = wrapper.instance();
|
||||||
|
instance.applyFilter(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
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.SELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(value)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('filter', () => {
|
||||||
|
const event = { target: { value: 'tester' } };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = mount(
|
||||||
|
<SelectFilter 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.SELECT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(event.target.value)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -9,7 +9,11 @@ jest.useFakeTimers();
|
|||||||
describe('Text Filter', () => {
|
describe('Text Filter', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
// onFilter(x)(y) = filter result
|
||||||
const onFilter = sinon.stub();
|
const onFilter = sinon.stub();
|
||||||
|
const onFilterFirstReturn = sinon.stub();
|
||||||
|
|
||||||
const column = {
|
const column = {
|
||||||
dataField: 'price',
|
dataField: 'price',
|
||||||
text: 'Price'
|
text: 'Price'
|
||||||
@@ -17,6 +21,9 @@ describe('Text Filter', () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
onFilter.reset();
|
onFilter.reset();
|
||||||
|
onFilterFirstReturn.reset();
|
||||||
|
|
||||||
|
onFilter.returns(onFilterFirstReturn);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('initialization', () => {
|
describe('initialization', () => {
|
||||||
@@ -58,7 +65,39 @@ describe('Text Filter', () => {
|
|||||||
|
|
||||||
it('should calling onFilter on componentDidMount', () => {
|
it('should calling onFilter on componentDidMount', () => {
|
||||||
expect(onFilter.calledOnce).toBeTruthy();
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.TEXT)).toBeTruthy();
|
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).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(
|
||||||
|
<TextFilter onFilter={ onFilter } column={ column } 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.TEXT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(filterValue)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setState correctly when exported function was executed', () => {
|
||||||
|
expect(instance.state.value).toEqual(filterValue);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,7 +153,9 @@ describe('Text Filter', () => {
|
|||||||
|
|
||||||
it('should calling onFilter correctly when props.defaultValue is changed', () => {
|
it('should calling onFilter correctly when props.defaultValue is changed', () => {
|
||||||
expect(onFilter.calledOnce).toBeTruthy();
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
expect(onFilter.calledWith(column, nextDefaultValue, FILTER_TYPE.TEXT)).toBeTruthy();
|
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(nextDefaultValue)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,8 +174,9 @@ describe('Text Filter', () => {
|
|||||||
|
|
||||||
it('should calling onFilter correctly', () => {
|
it('should calling onFilter correctly', () => {
|
||||||
expect(onFilter.calledOnce).toBeTruthy();
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
expect(onFilter.calledWith(
|
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||||
column, instance.props.defaultValue, FILTER_TYPE.TEXT)).toBeTruthy();
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -154,7 +196,9 @@ describe('Text Filter', () => {
|
|||||||
|
|
||||||
it('should calling onFilter correctly', () => {
|
it('should calling onFilter correctly', () => {
|
||||||
expect(onFilter.calledOnce).toBeTruthy();
|
expect(onFilter.calledOnce).toBeTruthy();
|
||||||
expect(onFilter.calledWith(column, filterText, FILTER_TYPE.TEXT)).toBeTruthy();
|
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||||
|
expect(onFilterFirstReturn.calledWith(filterText)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
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';
|
||||||
|
|
||||||
import { filters } from '../src/filter';
|
import { filters } from '../src/filter';
|
||||||
import { FILTER_TYPE } from '../src/const';
|
import { FILTER_TYPE } from '../src/const';
|
||||||
import { LIKE, EQ } from '../src/comparison';
|
import { LIKE, EQ, GT, GE, LT, LE, NE } from '../src/comparison';
|
||||||
|
|
||||||
const data = [];
|
const data = [];
|
||||||
for (let i = 0; i < 20; i += 1) {
|
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,14 +34,30 @@ describe('filter', () => {
|
|||||||
}, {
|
}, {
|
||||||
dataField: 'price',
|
dataField: 'price',
|
||||||
text: 'Price'
|
text: 'Price'
|
||||||
|
}, {
|
||||||
|
dataField: 'date',
|
||||||
|
text: 'Date'
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('text filter', () => {
|
describe('filterByText', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
filterFn = filters(store, columns, _);
|
filterFn = filters(store, columns, _);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when filter value is not a String', () => {
|
||||||
|
it('should transform to string and do the filter', () => {
|
||||||
|
currFilters.name = {
|
||||||
|
filterVal: 3,
|
||||||
|
filterType: FILTER_TYPE.TEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe(`when default comparator is ${LIKE}`, () => {
|
describe(`when default comparator is ${LIKE}`, () => {
|
||||||
it('should returning correct result', () => {
|
it('should returning correct result', () => {
|
||||||
currFilters.name = {
|
currFilters.name = {
|
||||||
@@ -55,6 +71,20 @@ describe('filter', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when caseSensitive is true', () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.name = {
|
||||||
|
filterVal: 'NAME',
|
||||||
|
caseSensitive: true,
|
||||||
|
filterType: FILTER_TYPE.TEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe(`when default comparator is ${EQ}`, () => {
|
describe(`when default comparator is ${EQ}`, () => {
|
||||||
it('should returning correct result', () => {
|
it('should returning correct result', () => {
|
||||||
currFilters.name = {
|
currFilters.name = {
|
||||||
@@ -71,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, _);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,12 +113,159 @@ 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('filterByNumber', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
filterFn = filters(store, columns, _);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when currFilters.filterVal.comparator is empty', () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: '', number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
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.number is empty', () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: EQ, number: '' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(data.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when currFilters.filterVal.comparator is ${EQ}`, () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: EQ, number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
|
||||||
|
currFilters.price.filterVal.number = '0';
|
||||||
|
result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when currFilters.filterVal.comparator is ${GT}`, () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: GT, number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(16);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when currFilters.filterVal.comparator is ${GE}`, () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: GE, number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(17);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when currFilters.filterVal.comparator is ${LT}`, () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: LT, number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when currFilters.filterVal.comparator is ${LE}`, () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: LE, number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when currFilters.filterVal.comparator is ${NE}`, () => {
|
||||||
|
it('should returning correct result', () => {
|
||||||
|
currFilters.price = {
|
||||||
|
filterVal: { comparator: NE, number: '203' },
|
||||||
|
filterType: FILTER_TYPE.NUMBER
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = filterFn(currFilters);
|
||||||
|
expect(result).toHaveLength(19);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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....
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -167,14 +167,14 @@ describe('Wrapper', () => {
|
|||||||
|
|
||||||
it('should setting store object correctly', () => {
|
it('should setting store object correctly', () => {
|
||||||
filterVals.forEach((filterVal) => {
|
filterVals.forEach((filterVal) => {
|
||||||
instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal);
|
||||||
expect(props.store.filtering).toBeFalsy();
|
expect(props.store.filtering).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setting state correctly', () => {
|
it('should setting state correctly', () => {
|
||||||
filterVals.forEach((filterVal) => {
|
filterVals.forEach((filterVal) => {
|
||||||
instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(0);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(0);
|
||||||
});
|
});
|
||||||
@@ -185,12 +185,12 @@ describe('Wrapper', () => {
|
|||||||
const filterVal = '3';
|
const filterVal = '3';
|
||||||
|
|
||||||
it('should setting store object correctly', () => {
|
it('should setting store object correctly', () => {
|
||||||
instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal);
|
||||||
expect(props.store.filters).toEqual(instance.state.currFilters);
|
expect(props.store.filters).toEqual(instance.state.currFilters);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setting state correctly', () => {
|
it('should setting state correctly', () => {
|
||||||
instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
||||||
});
|
});
|
||||||
@@ -203,7 +203,7 @@ describe('Wrapper', () => {
|
|||||||
props = createTableProps();
|
props = createTableProps();
|
||||||
props.remote = { filter: true };
|
props.remote = { filter: true };
|
||||||
createFilterWrapper(props);
|
createFilterWrapper(props);
|
||||||
instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not setting store object correctly', () => {
|
it('should not setting store object correctly', () => {
|
||||||
@@ -222,27 +222,27 @@ describe('Wrapper', () => {
|
|||||||
|
|
||||||
describe('combination', () => {
|
describe('combination', () => {
|
||||||
it('should setting store object correctly', () => {
|
it('should setting store object correctly', () => {
|
||||||
instance.onFilter(props.columns[1], '3', FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('3');
|
||||||
expect(props.store.filters).toEqual(instance.state.currFilters);
|
expect(props.store.filters).toEqual(instance.state.currFilters);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
||||||
|
|
||||||
instance.onFilter(props.columns[1], '2', FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('2');
|
||||||
expect(props.store.filters).toEqual(instance.state.currFilters);
|
expect(props.store.filters).toEqual(instance.state.currFilters);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
||||||
|
|
||||||
instance.onFilter(props.columns[2], '2', FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[2], FILTER_TYPE.TEXT)('2');
|
||||||
expect(props.store.filters).toEqual(instance.state.currFilters);
|
expect(props.store.filters).toEqual(instance.state.currFilters);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(2);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(2);
|
||||||
|
|
||||||
instance.onFilter(props.columns[2], '', FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[2], FILTER_TYPE.TEXT)('');
|
||||||
expect(props.store.filters).toEqual(instance.state.currFilters);
|
expect(props.store.filters).toEqual(instance.state.currFilters);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(1);
|
||||||
|
|
||||||
instance.onFilter(props.columns[1], '', FILTER_TYPE.TEXT);
|
instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('');
|
||||||
expect(props.store.filters).toEqual(instance.state.currFilters);
|
expect(props.store.filters).toEqual(instance.state.currFilters);
|
||||||
expect(instance.state.isDataChanged).toBeTruthy();
|
expect(instance.state.isDataChanged).toBeTruthy();
|
||||||
expect(Object.keys(instance.state.currFilters)).toHaveLength(0);
|
expect(Object.keys(instance.state.currFilters)).toHaveLength(0);
|
||||||
|
|||||||
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 @@
|
|||||||
# react-bootstrap-table2-pagination
|
# react-bootstrap-table2-paginator
|
||||||
|
|
||||||
`react-bootstrap-table2` separate the pagination code base to [`react-bootstrap-table2-pagination`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-paginator), so there's a little bit different when you use pagination. In the following, we are going to show you how to enable and configure the a pagination table
|
`react-bootstrap-table2` separate the pagination code base to [`react-bootstrap-table2-paginator`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-paginator), so there's a little bit different when you use pagination. In the following, we are going to show you how to enable and configure the a pagination table
|
||||||
|
|
||||||
**[Live Demo For Pagination](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination)**
|
**[Live Demo For Pagination](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination)**
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
## Install
|
## Install
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ npm install react-bootstrap-table2-pagination --save
|
$ npm install react-bootstrap-table2-paginator --save
|
||||||
```
|
```
|
||||||
|
|
||||||
## Add CSS
|
## Add CSS
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-paginator",
|
"name": "react-bootstrap-table2-paginator",
|
||||||
"version": "0.1.1",
|
"version": "0.1.5",
|
||||||
"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,4 +1,6 @@
|
|||||||
/* eslint no-mixed-operators: 0 */
|
/* eslint no-mixed-operators: 0 */
|
||||||
|
import Const from './const';
|
||||||
|
|
||||||
export default ExtendBase =>
|
export default ExtendBase =>
|
||||||
class PageResolver extends ExtendBase {
|
class PageResolver extends ExtendBase {
|
||||||
backToPrevPage() {
|
backToPrevPage() {
|
||||||
@@ -27,6 +29,23 @@ export default ExtendBase =>
|
|||||||
return pageStartIndex + totalPages - 1;
|
return pageStartIndex + totalPages - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculateFromTo() {
|
||||||
|
const {
|
||||||
|
dataSize,
|
||||||
|
currPage,
|
||||||
|
currSizePerPage,
|
||||||
|
pageStartIndex
|
||||||
|
} = this.props;
|
||||||
|
const offset = Math.abs(Const.PAGE_START_INDEX - pageStartIndex);
|
||||||
|
|
||||||
|
let from = ((currPage - pageStartIndex) * currSizePerPage);
|
||||||
|
from = dataSize === 0 ? 0 : from + 1;
|
||||||
|
let to = Math.min((currSizePerPage * (currPage + offset) - 1), dataSize);
|
||||||
|
if (to >= dataSize) to -= 1;
|
||||||
|
|
||||||
|
return [from, to];
|
||||||
|
}
|
||||||
|
|
||||||
calculatePages(
|
calculatePages(
|
||||||
totalPages = this.state.totalPages,
|
totalPages = this.state.totalPages,
|
||||||
lastPage = this.state.lastPage) {
|
lastPage = this.state.lastPage) {
|
||||||
|
|||||||
16
packages/react-bootstrap-table2-paginator/src/pagination-total.js
vendored
Normal file
16
packages/react-bootstrap-table2-paginator/src/pagination-total.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const PaginationTotal = props => (
|
||||||
|
<span className="react-bootstrap-table-pagination-total">
|
||||||
|
Showing rows { props.from } to { props.to + 1 } of { props.dataSize }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
PaginationTotal.propTypes = {
|
||||||
|
from: PropTypes.number.isRequired,
|
||||||
|
to: PropTypes.number.isRequired,
|
||||||
|
dataSize: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaginationTotal;
|
||||||
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
|
|||||||
import pageResolver from './page-resolver';
|
import pageResolver from './page-resolver';
|
||||||
import SizePerPageDropDown from './size-per-page-dropdown';
|
import SizePerPageDropDown from './size-per-page-dropdown';
|
||||||
import PaginationList from './pagination-list';
|
import PaginationList from './pagination-list';
|
||||||
|
import PaginationTotal from './pagination-total';
|
||||||
import Const from './const';
|
import Const from './const';
|
||||||
|
|
||||||
class Pagination extends pageResolver(Component) {
|
class Pagination extends pageResolver(Component) {
|
||||||
@@ -86,16 +87,35 @@ 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,
|
||||||
|
dataSize,
|
||||||
|
paginationTotalRenderer,
|
||||||
sizePerPageList,
|
sizePerPageList,
|
||||||
currSizePerPage,
|
currSizePerPage,
|
||||||
hideSizePerPage,
|
hideSizePerPage,
|
||||||
hidePageListOnlyOnePage
|
hidePageListOnlyOnePage
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage);
|
const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage);
|
||||||
|
const [from, to] = this.calculateFromTo();
|
||||||
const pageListClass = cs(
|
const pageListClass = cs(
|
||||||
'react-bootstrap-table-pagination-list',
|
'react-bootstrap-table-pagination-list',
|
||||||
'col-md-6 col-xs-6 col-sm-6 col-lg-6', {
|
'col-md-6 col-xs-6 col-sm-6 col-lg-6', {
|
||||||
@@ -117,6 +137,15 @@ class Pagination extends pageResolver(Component) {
|
|||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
showTotal ?
|
||||||
|
this.setTotal(
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
dataSize,
|
||||||
|
paginationTotalRenderer
|
||||||
|
) : null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={ pageListClass }>
|
<div className={ pageListClass }>
|
||||||
<PaginationList pages={ pages } onPageChange={ this.handleChangePage } />
|
<PaginationList pages={ pages } onPageChange={ this.handleChangePage } />
|
||||||
@@ -135,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,
|
||||||
@@ -154,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,
|
||||||
|
|||||||
@@ -54,11 +54,14 @@ export default (Base, {
|
|||||||
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;
|
|
||||||
needNewState = true;
|
needNewState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof currPage === 'undefined') {
|
||||||
|
currPage = typeof pageStartIndex !== 'undefined' ? pageStartIndex : Const.PAGE_START_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof sizePerPage !== 'undefined') {
|
if (typeof sizePerPage !== 'undefined') {
|
||||||
currSizePerPage = sizePerPage;
|
currSizePerPage = sizePerPage;
|
||||||
needNewState = true;
|
needNewState = true;
|
||||||
@@ -145,6 +148,8 @@ export default (Base, {
|
|||||||
alwaysShowAllBtns={ alwaysShowAllBtns }
|
alwaysShowAllBtns={ alwaysShowAllBtns }
|
||||||
hideSizePerPage={ hideSizePerPage }
|
hideSizePerPage={ hideSizePerPage }
|
||||||
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
|
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
|
||||||
|
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 }
|
||||||
|
|||||||
@@ -110,6 +110,19 @@ describe('PageResolver', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('calculateFromTo', () => {
|
||||||
|
const props = createMockProps();
|
||||||
|
beforeEach(() => {
|
||||||
|
const mockElement = React.createElement(MockComponent, props, null);
|
||||||
|
wrapper = shallow(mockElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return correct array with from and to value', () => {
|
||||||
|
const instance = wrapper.instance();
|
||||||
|
expect(instance.calculateFromTo()).toEqual([1, props.currSizePerPage - 1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('calculateTotalPage', () => {
|
describe('calculateTotalPage', () => {
|
||||||
const props = createMockProps();
|
const props = createMockProps();
|
||||||
|
|
||||||
|
|||||||
@@ -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,6 +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')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('componentWillReceiveProps', () => {
|
describe('componentWillReceiveProps', () => {
|
||||||
@@ -176,10 +177,11 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when nextProps.isDataChanged is true and options.pageStartIndex is existing', () => {
|
describe('when nextProps.isDataChanged is true, currPage is undefined and options.pageStartIndex exists', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
nextProps.isDataChanged = true;
|
nextProps.isDataChanged = true;
|
||||||
nextProps.pagination.options.pageStartIndex = 0;
|
nextProps.pagination.options.pageStartIndex = 0;
|
||||||
|
instance.state.currPage = undefined;
|
||||||
instance.componentWillReceiveProps(nextProps);
|
instance.componentWillReceiveProps(nextProps);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -247,6 +249,20 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when options.showTotal is defined', () => {
|
||||||
|
const props = createTableProps({ options: { showTotal: true } });
|
||||||
|
beforeEach(() => {
|
||||||
|
createPaginationWrapper(props);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render Pagination correctly', () => {
|
||||||
|
const pagination = wrapper.find(Pagination);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(pagination.length).toBe(1);
|
||||||
|
expect(pagination.prop('showTotal')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when options.pageStartIndex is defined', () => {
|
describe('when options.pageStartIndex is defined', () => {
|
||||||
const pageStartIndex = -1;
|
const pageStartIndex = -1;
|
||||||
const props = createTableProps({ options: { pageStartIndex } });
|
const props = createTableProps({ options: { pageStartIndex } });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table-next",
|
"name": "react-bootstrap-table-next",
|
||||||
"version": "0.1.1",
|
"version": "0.1.14",
|
||||||
"description": "Next generation of react-bootstrap-table",
|
"description": "Next generation of react-bootstrap-table",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
3
packages/react-bootstrap-table2/src/body.js
vendored
3
packages/react-bootstrap-table2/src/body.js
vendored
@@ -35,6 +35,9 @@ const Body = (props) => {
|
|||||||
|
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication;
|
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication;
|
||||||
|
if (!indication) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
|
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
|
||||||
} else {
|
} else {
|
||||||
const nonEditableRows = cellEdit.nonEditableRows || [];
|
const nonEditableRows = cellEdit.nonEditableRows || [];
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -42,6 +45,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
store,
|
store,
|
||||||
columns,
|
columns,
|
||||||
keyField,
|
keyField,
|
||||||
|
id,
|
||||||
|
classes,
|
||||||
striped,
|
striped,
|
||||||
hover,
|
hover,
|
||||||
bordered,
|
bordered,
|
||||||
@@ -50,15 +55,18 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
caption,
|
caption,
|
||||||
rowStyle,
|
rowStyle,
|
||||||
rowClasses,
|
rowClasses,
|
||||||
|
wrapperClasses,
|
||||||
rowEvents
|
rowEvents
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses);
|
||||||
|
|
||||||
const tableClass = cs('table', {
|
const tableClass = cs('table', {
|
||||||
'table-striped': striped,
|
'table-striped': striped,
|
||||||
'table-hover': hover,
|
'table-hover': hover,
|
||||||
'table-bordered': bordered,
|
'table-bordered': bordered,
|
||||||
'table-condensed': condensed
|
'table-condensed': condensed
|
||||||
});
|
}, classes);
|
||||||
|
|
||||||
const cellSelectionInfo = this.resolveSelectRowProps({
|
const cellSelectionInfo = this.resolveSelectRowProps({
|
||||||
onRowSelect: this.props.onRowSelect
|
onRowSelect: this.props.onRowSelect
|
||||||
@@ -70,16 +78,19 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
allRowsSelected: isSelectedAll(store)
|
allRowsSelected: isSelectedAll(store)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tableCaption = (caption && <Caption>{ caption }</Caption>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="react-bootstrap-table">
|
<div className={ tableWrapperClass }>
|
||||||
<table className={ tableClass }>
|
<table id={ id } className={ tableClass }>
|
||||||
<Caption>{ caption }</Caption>
|
{ tableCaption }
|
||||||
<Header
|
<Header
|
||||||
columns={ columns }
|
columns={ columns }
|
||||||
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
|
||||||
@@ -114,6 +125,9 @@ BootstrapTable.propTypes = {
|
|||||||
striped: PropTypes.bool,
|
striped: PropTypes.bool,
|
||||||
bordered: PropTypes.bool,
|
bordered: PropTypes.bool,
|
||||||
hover: PropTypes.bool,
|
hover: PropTypes.bool,
|
||||||
|
id: PropTypes.string,
|
||||||
|
classes: PropTypes.string,
|
||||||
|
wrapperClasses: PropTypes.string,
|
||||||
condensed: PropTypes.bool,
|
condensed: PropTypes.bool,
|
||||||
caption: PropTypes.oneOfType([
|
caption: PropTypes.oneOfType([
|
||||||
PropTypes.node,
|
PropTypes.node,
|
||||||
@@ -132,7 +146,9 @@ 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,
|
||||||
@@ -143,10 +159,12 @@ BootstrapTable.propTypes = {
|
|||||||
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
|
||||||
})),
|
})),
|
||||||
|
defaultSortDirection: PropTypes.oneOf([Const.SORT_DESC, Const.SORT_ASC]),
|
||||||
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 = {
|
||||||
|
|||||||
9
packages/react-bootstrap-table2/src/cell.js
vendored
9
packages/react-bootstrap-table2/src/cell.js
vendored
@@ -39,7 +39,6 @@ class Cell extends Component {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
const {
|
const {
|
||||||
dataField,
|
dataField,
|
||||||
hidden,
|
|
||||||
formatter,
|
formatter,
|
||||||
formatExtraData,
|
formatExtraData,
|
||||||
style,
|
style,
|
||||||
@@ -80,10 +79,6 @@ class Cell extends Component {
|
|||||||
_.isFunction(align) ? align(content, row, rowIndex, columnIndex) : align;
|
_.isFunction(align) ? align(content, row, rowIndex, columnIndex) : align;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hidden) {
|
|
||||||
cellStyle.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cellClasses) cellAttrs.className = cellClasses;
|
if (cellClasses) cellAttrs.className = cellClasses;
|
||||||
|
|
||||||
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
|
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
|
||||||
@@ -93,7 +88,9 @@ class Cell extends Component {
|
|||||||
cellAttrs.onDoubleClick = this.handleEditingCell;
|
cellAttrs.onDoubleClick = this.handleEditingCell;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<td { ...cellAttrs }>{ content }</td>
|
<td { ...cellAttrs }>
|
||||||
|
{ typeof content === 'boolean' ? `${content}` : content }
|
||||||
|
</td>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ const HeaderCell = (props) => {
|
|||||||
sorting,
|
sorting,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
isLastSorting,
|
isLastSorting,
|
||||||
onFilter
|
onFilter,
|
||||||
|
onExternalFilter
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
text,
|
text,
|
||||||
sort,
|
sort,
|
||||||
filter,
|
filter,
|
||||||
hidden,
|
filterRenderer,
|
||||||
headerTitle,
|
headerTitle,
|
||||||
headerAlign,
|
headerAlign,
|
||||||
headerFormatter,
|
headerFormatter,
|
||||||
@@ -58,10 +59,6 @@ const HeaderCell = (props) => {
|
|||||||
cellStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign;
|
cellStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hidden) {
|
|
||||||
cellStyle.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sort) {
|
if (sort) {
|
||||||
const customClick = cellAttrs.onClick;
|
const customClick = cellAttrs.onClick;
|
||||||
cellAttrs.onClick = (e) => {
|
cellAttrs.onClick = (e) => {
|
||||||
@@ -94,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 } />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,11 +132,17 @@ HeaderCell.propTypes = {
|
|||||||
attrs: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
attrs: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
sort: PropTypes.bool,
|
sort: PropTypes.bool,
|
||||||
sortFunc: PropTypes.func,
|
sortFunc: PropTypes.func,
|
||||||
|
onSort: PropTypes.func,
|
||||||
|
editor: PropTypes.object,
|
||||||
editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
||||||
editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
|
editorStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
|
editorClasses: PropTypes.oneOfType([PropTypes.string, 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;
|
||||||
|
|||||||
36
packages/react-bootstrap-table2/src/header.js
vendored
36
packages/react-bootstrap-table2/src/header.js
vendored
@@ -15,7 +15,8 @@ const Header = (props) => {
|
|||||||
onFilter,
|
onFilter,
|
||||||
sortField,
|
sortField,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
selectRow
|
selectRow,
|
||||||
|
onExternalFilter
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -27,20 +28,24 @@ const Header = (props) => {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
columns.map((column, i) => {
|
columns.map((column, i) => {
|
||||||
const currSort = column.dataField === sortField;
|
if (!column.hidden) {
|
||||||
const isLastSorting = column.dataField === sortField;
|
const currSort = column.dataField === sortField;
|
||||||
|
const isLastSorting = column.dataField === sortField;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderCell
|
<HeaderCell
|
||||||
index={ i }
|
index={ i }
|
||||||
key={ column.dataField }
|
key={ column.dataField }
|
||||||
column={ column }
|
column={ column }
|
||||||
onSort={ onSort }
|
onSort={ onSort }
|
||||||
sorting={ currSort }
|
sorting={ currSort }
|
||||||
onFilter={ onFilter }
|
onFilter={ onFilter }
|
||||||
sortOrder={ sortOrder }
|
onExternalFilter={ onExternalFilter }
|
||||||
isLastSorting={ isLastSorting }
|
sortOrder={ sortOrder }
|
||||||
/>);
|
isLastSorting={ isLastSorting }
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -54,7 +59,8 @@ 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
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
export default ExtendBase =>
|
export default ExtendBase =>
|
||||||
class ColumnResolver extends ExtendBase {
|
class ColumnResolver extends ExtendBase {
|
||||||
visibleColumnSize() {
|
visibleColumnSize(includeSelectColumn = true) {
|
||||||
return this.props.columns.length;
|
const columnLen = this.props.columns.filter(c => !c.hidden).length;
|
||||||
|
if (!includeSelectColumn) return columnLen;
|
||||||
|
if (this.props.selectRow && !this.props.selectRow.hideSelectColumn) {
|
||||||
|
return columnLen + 1;
|
||||||
|
}
|
||||||
|
return columnLen;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import _ from '../utils';
|
|||||||
export default ExtendBase =>
|
export default ExtendBase =>
|
||||||
class TableResolver extends ColumnResolver(ExtendBase) {
|
class TableResolver extends ColumnResolver(ExtendBase) {
|
||||||
validateProps() {
|
validateProps() {
|
||||||
const { columns, keyField } = this.props;
|
const { keyField } = this.props;
|
||||||
if (!keyField) {
|
if (!keyField) {
|
||||||
throw new Error('Please specify a field as key via keyField');
|
throw new Error('Please specify a field as key via keyField');
|
||||||
}
|
}
|
||||||
if (this.visibleColumnSize(columns) <= 0) {
|
if (this.visibleColumnSize(false) <= 0) {
|
||||||
throw new Error('No any visible columns detect');
|
throw new Error('No visible columns detected');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user