Compare commits

...

42 Commits

Author SHA1 Message Date
AllenFang
a556bd23ef Publish
- react-bootstrap-table2-editor@0.0.3
 - react-bootstrap-table2-example@0.0.3
 - react-bootstrap-table2-filter@0.0.3
 - react-bootstrap-table2-overlay@0.0.3
 - react-bootstrap-table2-paginator@0.0.3
 - react-bootstrap-table-next@0.0.3
2018-01-21 13:59:30 +08:00
AllenFang
b2e6bf93fb tweak pagination factory name 2018-01-20 17:53:58 +08:00
AllenFang
5f7c55aad4 drop start scripts 2018-01-20 15:27:08 +08:00
AllenFang
b4f7028b8b no publish 2018-01-20 15:27:08 +08:00
AllenFang
50a5bd3694 refine file name 2018-01-20 15:27:08 +08:00
AllenFang
9b3abac56d react-bootstrap-table2 -> react-bootstrap-table-next 2018-01-20 14:55:58 +08:00
AllenFang
1ef006e4c2 add README.md 2018-01-20 14:44:59 +08:00
AllenFang
42339b76aa tweak package.json 2018-01-20 13:34:27 +08:00
AllenFang
0d3b76b6a3 README.md 2018-01-20 11:21:11 +08:00
Allen
28240391bb Merge pull request #167 from react-bootstrap-table/Chun-MingChen-prod-setup
Production build
2018-01-18 23:17:37 +08:00
AllenFang
1cedea567c remove lerna-changelog 2018-01-18 22:56:18 +08:00
AllenFang
a9dd05d7cc fix entry point changed 2018-01-18 22:53:51 +08:00
AllenFang
41d76a08ce gulp build for style, scripts and umd 2018-01-18 21:49:33 +08:00
AllenFang
5d0b0af97a build sass 2018-01-16 22:54:02 +08:00
AllenFang
4bd73056d0 babel build 2018-01-16 00:04:14 +08:00
AllenFang
ec705f2651 umd build 2018-01-14 23:43:21 +08:00
AllenFang
3a8390c49e react-bootstrap-table2-example depend other packages via webpack resolver instead of node modules 2018-01-14 18:29:27 +08:00
AllenFang
afc742c205 no babel-cli build per repo 2018-01-14 15:56:39 +08:00
AllenFang
be4211b3c9 no publish to gh-pages 2018-01-14 15:53:27 +08:00
AllenFang
6c0fc4ffb4 Merge branch 'prod-setup' of https://github.com/Chun-MingChen/react-bootstrap-table2 into Chun-MingChen-prod-setup 2018-01-14 15:41:46 +08:00
Allen
55fe0075b1 Merge pull request #165 from react-bootstrap-table/enhance/cell-edit-as-package
react-bootstrap-table2-editor
2018-01-07 14:18:59 +08:00
AllenFang
618346b845 patch docs for cell edit 2018-01-07 14:07:17 +08:00
AllenFang
e46d83762d fix EditingCell liftcycle bug 2018-01-07 14:02:50 +08:00
AllenFang
9428f2d9b7 refine cell edit tests 2018-01-07 11:20:49 +08:00
AllenFang
21344ec4b3 refine cell edit stories 2018-01-07 11:20:49 +08:00
AllenFang
39be018327 move cell edit logic to react-bootstrap-table2-editor 2018-01-07 11:20:32 +08:00
Chun-MingChen
3649f83eaf select lerna-changelog to generate change log 2018-01-07 01:46:52 +08:00
Chun-MingChen
a37ef6883d compile with babel 2018-01-07 01:46:52 +08:00
Chun-MingChen
383cfbab57 add package babel-cli 2018-01-07 01:29:13 +08:00
Chun-MingChen
cb1041b9d7 auto release for storybook
* deploy subdirectory of storybook-static to branch gh-pages
2018-01-07 01:29:13 +08:00
Chun-MingChen
6e4ca34626 add dependency git-directory-deploy
* Deploy a subdirectory from a git repo to a different branch.
2018-01-06 19:43:28 +08:00
Chun-MingChen
19cca1215f add dependency rimraf
* clean built files for gh_pages
2018-01-06 19:43:03 +08:00
Allen
6913434714 fix #161
Refine cell edit remote mode
2018-01-06 13:48:07 +08:00
AllenFang
d5f7ae5edb refined docs for remote cell edit 2018-01-04 23:45:40 +08:00
AllenFang
beafef9661 patch tests for refining remote cell edit 2018-01-04 23:45:40 +08:00
AllenFang
a50a12426a refine remote cell edit 2018-01-04 23:42:17 +08:00
Allen
fcf7800f96 fix #152
implement remote sorting
2017-12-28 17:58:18 +08:00
AllenFang
01337f50a7 implement remote sorting 2017-12-27 23:31:16 +08:00
Allen
bdfc4ebcad Merge pull request #158 from react-bootstrap-table/enhance/refactoring
Refarcotring Wrapper
2017-12-25 17:46:23 +08:00
AllenFang
fb81595f73 refactoring wrapper mechanism 2017-12-25 17:32:14 +08:00
AllenFang
3bfeec7946 fix bug for onTableChange argument change 2017-12-25 17:32:14 +08:00
AllenFang
4c89f91a83 implement remote resolver 2017-12-25 17:32:14 +08:00
148 changed files with 5259 additions and 3117 deletions

7
.gitignore vendored
View File

@@ -15,3 +15,10 @@ lerna-debug.log
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# gh-pages
storybook-static
# build
lib
dist

7
.npmignore Normal file
View File

@@ -0,0 +1,7 @@
node_modules
.DS_Store
*~
*.sublime-project
*.sublime-workspace
*.idea
*.iml

View File

@@ -1,25 +1,12 @@
# react-bootstrap-table2 # 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)
## The problems/features I want to solve ## Development
* Performance Please check [development guide](./docs/development.md).
* Fully compatiable with bootstrap 3 and 4(`react-bootstrap-table@4.0.0` already done)
* Clean Code and Testing ## Usage
* Decrease the size of bundled file See [getting started](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/getting-started.html).
* **Split module/functionality from core module, make core module more lightweight**
* Use [`storybook`](https://github.com/storybooks/storybook) to build examples ## Roadmap
* Support the aggregation(summary) view See [release plans](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html).
* Support the table footer
* Support column/row span on header and body
* Support sticky header
* Support table section([react-bootstrap-table#721](https://github.com/AllenFang/react-bootstrap-table/pull/721))
* Handle events well
* Fix unalign issues
* Make **stateless** table more easy to use(`react-bootstrap-table` alread have `remote` mode but have some bugs)
* Customizable table
* Support the nested data([react-bootstrap-table#50](https://github.com/AllenFang/react-bootstrap-table/issues/50◊))
* Consider to support column resize
* Consider to make animation on `react-bootstrap-table2` more easy
## The feature may lost on react-bootstrap-table
* Have a great chance that I don't support the vertical scrollbar on table

View File

@@ -40,7 +40,13 @@ This is a chance that you can connect to your remote server or database to manip
For flexibility reason, you can control what functionality should be handled on remote via a object return: For flexibility reason, you can control what functionality should be handled on remote via a object return:
```js ```js
remote={ { filter: true } } remote={ {
filter: true,
pagination: true,
filter: true,
sort: true,
cellEdit: true
} }
``` ```
In above case, only column filter will be handled on remote. In above case, only column filter will be handled on remote.
@@ -53,20 +59,20 @@ A special case for remote pagination:
remote={ { pagination: true, filter: false, sort: false } } remote={ { pagination: true, filter: false, sort: false } }
``` ```
In pagination case, 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-table` only know the data of current page, but filtering, searching or sort need to work on overall datas. 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.
### <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-table` will attend to render a overlay on table via [`overlay`](#overlay) prop, if [`overlay`](#overlay) prop is not given, `react-bootstrap-table` 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-table-overlay` can be a good option for you: `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:
```sh ```sh
$ npm install react-bootstrap-table-overlay $ npm install react-bootstrap-table2-overlay
``` ```
```js ```js
import overlayFactory from 'react-bootstrap-table-overlay'; import overlayFactory from 'react-bootstrap-table2-overlay';
<BootstrapTable <BootstrapTable
data={ data } data={ data }
@@ -249,13 +255,23 @@ There's only two arguments will be passed to `onTableChange`: `type` and `newSta
* `filter` * `filter`
* `pagination` * `pagination`
* `sort`
* `cellEdit`
Following is a shape of `newState` Following is a shape of `newState`
```js ```js
{ {
page, // newest page page, // newest page
sizePerPage, //newest sizePerPage sizePerPage, // newest sizePerPage
filters // an object which have current filter status per column sortField, // newest sort field
sortOrder, // newest sort order
filters, // an object which have current filter status per column
data, // when you enable remote sort, you may need to base on data to sort if data is filtered/searched
cellEdit: { // You can only see this prop when type is cellEdit
rowId,
dataField,
newValue
}
} }
``` ```

View File

@@ -1,3 +1,10 @@
# Cell Editing
Before start to use cell edit, please remember to install `react-bootstrap-table2-editor`
```sh
$ npm install react-bootstrap-table2-editor --save
```
# Properties on cellEdit prop # Properties on cellEdit prop
* [mode (**required**)](#mode) * [mode (**required**)](#mode)
* [blurToSave](#blurToSave) * [blurToSave](#blurToSave)
@@ -5,8 +12,6 @@
* [timeToCloseMessage](#timeToCloseMessage) * [timeToCloseMessage](#timeToCloseMessage)
* [beforeSaveCell](#beforeSaveCell) * [beforeSaveCell](#beforeSaveCell)
* [afterSaveCell](#afterSaveCell) * [afterSaveCell](#afterSaveCell)
* [onUpdate](#onUpdate)
* [editing](#editing)
* [errorMessage](#errorMessage) * [errorMessage](#errorMessage)
* [onErrorMessageDisappear](#onErrorMessageDisappear) * [onErrorMessageDisappear](#onErrorMessageDisappear)
@@ -21,9 +26,7 @@ Following is the shape of `cellEdit` object:
mode: 'click', mode: 'click',
blurToSave: true, blurToSave: true,
timeToCloseMessage: 2500, timeToCloseMessage: 2500,
editing: false|true,
errorMessage: '', errorMessage: '',
onUpdate: (rowId, dataField, newValue) => { ... },
beforeSaveCell: (oldValue, newValue, row, column) => { ... }, beforeSaveCell: (oldValue, newValue, row, column) => { ... },
afterSaveCell: (oldValue, newValue, row, column) => { ... }, afterSaveCell: (oldValue, newValue, row, column) => { ... },
onErrorMessageDisappear: () => { ... }, onErrorMessageDisappear: () => { ... },
@@ -63,74 +66,9 @@ const cellEdit = {
}; };
``` ```
### <a name='onUpdate'>cellEdit.onUpdate - [Function]</a>
If you want to control the cell updating process by yourself, for example, connect with `Redux` or saving data to backend database, `cellEdit.onUpdate` is a great chance you can work on it.
Firsylt, `react-bootstrap-table2` allow `cellEdit.onUpdate` to return a promise:
```js
const cellEdit = {
// omit...
onUpdate: (rowId, dataField, newValue) => {
return apiCall().then(response => {
console.log('update cell to backend successfully');
// Actually, you dont do any thing here, we will update the new value when resolve your promise
})
.catch(err => throw new Error(err.message));
}
};
```
If your promise is resolved successfully, `react-bootstrap-table2` will default help you to update the new cell value.
If your promise is resolved failure, you can throw an `Error` instance, `react-bootstrap-table2` will show up the error message (Same behavior like [`column.validator`](./columns.md#validator)).
In some case, backend will return a new value to client side and you want to apply this new value instead of the value that user input. In this situation, you can return an object which contain a `value` property:
```js
const cellEdit = {
// omit...
onUpdate: (rowId, dataField, newValue) => {
return apiCall().then(response => {
return { value: response.value }; // response.value is from your backend api
})
.catch(err => throw new Error(err.message));
}
};
```
If your application integgrate with `Redux`, you may need to dispatch an action in `cellEdit.onUpdate` callback. In this circumstances, you need to return `false` explicity which `react-bootstrap-table2` will stop any operation internally and wait rerender by your application.
In a simple redux application, you probably need to handle those props by your application:
* [`cellEdit.editing`](#editing): Is cell still on editing or not? This value should always be `true` when saving cell failure.
* [`cellEdit.errorMessage`](#errorMessage): Error message when save the cell failure.
* [`cellEdit.onErrorMessageDisappear`](#onErrorMessageDisappear): This callback will be called when error message alert closed automatically.
* `cellEdit.onUpdate`
```js
const cellEdit = {
editing: this.props.editing,
errorMessage: this.props.errorMessage,
onErrorMessageDisappear: () => {
// cleanErrorMessage is an action creator
this.props.dispatch(cleanErrorMessage());
},
onUpdate: (rowId, dataField, newValue) => {
// updateCell is an action creator
this.props.dispatch(updateCell(rowId, dataField, newValue)));
return false; // Have to return false here
}
};
```
Please check [this](https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/develop/packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-with-redux-table.js) exmaple to learn how use `cellEdit` with a redux application
### <a name='editing'>cellEdit.editing - [Bool]</a>
This only used when you want to control cell saving externally, `cellEdit.editing` will be a flag to tell `react-bootstrap-table2` whether currecnt editing cell is still editing or not. Because, it's possible that some error happen when you saving cell, in this situation, you need to configre this value as `false` to keep the cell as edtiable and show up an error message.
### <a name='errorMessage'>cellEdit.errorMessage - [String]</a> ### <a name='errorMessage'>cellEdit.errorMessage - [String]</a>
Same as [`cellEdit.editing`](#editing). This prop is not often used. Only used when you keep the error message in your application state. This prop is not often used. Only used when you want to keep the error message in your application state and also handle the cell editing on remote mode.
### <a name='onErrorMessageDisappear'>cellEdit.onErrorMessageDisappear - [Function]</a> ### <a name='onErrorMessageDisappear'>cellEdit.onErrorMessageDisappear - [Function]</a>
This callback function will be called when error message discard. This callback function will be called when error message discard so that you can sync the newest error message to your state if you have.

View File

@@ -73,7 +73,7 @@ dataField: 'address.city'
``` ```
## <a name='text'>column.text (**required**) - [String]</a> ## <a name='text'>column.text (**required**) - [String]</a>
`text` will be apply as the column text in header column, if your header is not only text and you want to customize your header column, please check [`column.headerFormatter`](#headerFormatter) `text` will be the column text in header column by default, if your header is not only text or you want to customize the header column, please check [`column.headerFormatter`](#headerFormatter)
## <a name='hidden'>column.hidden - [Bool]</a> ## <a name='hidden'>column.hidden - [Bool]</a>
`hidden` allow you to hide column when `true` given. `hidden` allow you to hide column when `true` given.
@@ -89,9 +89,9 @@ dataField: 'address.city'
## <a name='headerFormatter'>column.headerFormatter - [Function]</a> ## <a name='headerFormatter'>column.headerFormatter - [Function]</a>
`headerFormatter` allow you to customize the header column and only accept a callback function which take three arguments and a JSX/String are expected for return. `headerFormatter` allow you to customize the header column and only accept a callback function which take three arguments and a JSX/String are expected for return.
* `column`: column object itself * `column`: current column object itself
* `colIndex` * `colIndex`: index of current column
* `components`: it's an object which contain all of other react element, like sort caret or filter etc. * `components`: an object which contain all of other react element, like sort caret or filter etc.
The third argument: `components` have following specified properties: The third argument: `components` have following specified properties:
```js ```js
@@ -131,7 +131,7 @@ It's availabe to have custom class on table column:
classes: 'id-custom-cell' classes: 'id-custom-cell'
} }
``` ```
In addition, `classes` also accept a callback function which have more power to custom the css class on each columns. This callback function take `4` arguments and a `string` is expect to return: In addition, `classes` also accept a callback function which have more power to custom the css class on each columns. This callback function take **4** arguments and a `String` is expected to return::
```js ```js
@@ -148,7 +148,7 @@ In addition, `classes` also accept a callback function which have more power to
**Return value** **Return value**
A new `String` will be the result of 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 availabe to have customized class on table header column:
@@ -185,7 +185,7 @@ It's availabe to have custom style on table column:
} }
``` ```
In addition, similar to [`column.classes`](#classes), `style` also accept a callback function which have more power to customize the `inline style` on each columns. This callback function takes `4` arguments and an `Object` is expect to return: In addition, similar to [`column.classes`](#classes), `style` also accept a callback function which have more power to customize the `inline style` on each columns. This callback function takes **4** arguments and an `Object` is expect to return:
```js ```js
@@ -215,7 +215,7 @@ It's availabe to have customized inline-style on table header column:
} }
``` ```
Moreover, it also accept a callback function which takes 2 arguments and an `Object` is expect to return: Moreover, it also accept a callback function which takes **2** arguments and an `Object` is expect to return:
```js ```js
{ {
@@ -233,7 +233,7 @@ A new `Object` will be the result of element headerStyle.
## <a name='title'>column.title - [Bool | Function]</a> ## <a name='title'>column.title - [Bool | Function]</a>
`react-bootstrap-table2` is disable [`HTML title`](https://www.w3schools.com/tags/tag_title.asp) as default. You can assign `title` as `true` to enable the HTML title on table column and take `cell content` as default value. Additionally, you could customize title via a callback. It takes `4` arguments and a `String` is expect to return: `react-bootstrap-table2` is disable [`HTML title`](https://www.w3schools.com/tags/tag_title.asp) as default. You can assign `title` as `true` to enable the HTML title on table column and take `cell content` as default value. Additionally, you could customize title via a callback. It takes **4** arguments and a `String` is expect to return:
```js ```js
@@ -282,7 +282,7 @@ A new `String` will be the result of element headerTitle.
## <a name='align'>column.align - [String | Function]</a> ## <a name='align'>column.align - [String | Function]</a>
You can configure the [CSS text-align](https://www.w3schools.com/cssref/pr_text_text-align.asp) for table column by `align` property. You can configure the [CSS text-align](https://www.w3schools.com/cssref/pr_text_text-align.asp) for table column by `align` property.
Besides, `align` also accept a callback function for dynamically setting text align. It takes `4` arguments and a `String` is expect to return: Besides, `align` also accept a callback function for dynamically setting text align. It takes **4** arguments and a `String` is expect to return:
```js ```js
{ {
@@ -385,14 +385,14 @@ Not only `Object`, `callback function` is also acceptable. It takes `4` argument
A new `Object` will be the result of element HTML attributes. 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 priorty and it will be overwrited.
```js ```js
{ {
// omit... // omit...
title: true, // it will be chosen. title: true, // get higher priority
attrs: { title: 'test' } attrs: { title: 'test' }
} }
``` ```
@@ -409,7 +409,7 @@ If `column.classes`, `column.style`, `column.title`, `column.hidden` or `column.
} }
``` ```
Additionally, customize the header attributes by a `2-arguments` callback function: Additionally, customize the header attributes by a **2** arguments callback function:
```js ```js
{ {
@@ -556,4 +556,25 @@ 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>
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:
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of current row.
**Return value**
A final `String` value you want to be filtered.
```js
// omit...
{
dataField: 'price',
text: 'Product Price',
filter: textFilter(),
filterValue: (cell, row) => owners[cell]
}
```

View File

@@ -9,7 +9,7 @@ $ lerna bootstrap # ./node_modules/.bin/lerna bootstrap
``` ```
### Development ### Development
```bash ```bash
$ npm start $ npm run storybook
``` ```
### Launch StoryBook ### Launch StoryBook

View File

@@ -2,13 +2,10 @@
# Row selection # Row selection
`react-bootstrap-table2` supports the row selection feature. By passing prop `selectRow` to enable row selection. When you enable this feature, `react-bootstrap-table2` will append a new selection column at first. `react-bootstrap-table2` supports the row selection feature. By passing prop `selectRow` to enable row selection. When you enable this feature, `react-bootstrap-table2` will append a new selection column at first.
## Required
## Available properties
The following are available properties in `selectRow`:
#### Required
* [mode (**required**)](#mode) * [mode (**required**)](#mode)
## Optional
* [style](#style) * [style](#style)
* [classes)](#classes) * [classes)](#classes)
* [bgColor](#bgColor) * [bgColor](#bgColor)
@@ -19,15 +16,13 @@ The following are available properties in `selectRow`:
* [onSelectAll](#onSelectAll) * [onSelectAll](#onSelectAll)
* [hideSelectColumn](#hideSelectColumn) * [hideSelectColumn](#hideSelectColumn)
#### Optional ### <a name="mode">selectRow.mode - [String]</a>
## <a name="mode">selectRow.mode - [String]</a>
Specifying the selection way for `single(radio)` or `multiple(checkbox)`. If `radio` was assigned, there will be a radio button in the selection column; otherwise, the `checkbox` instead. Specifying the selection way for `single(radio)` or `multiple(checkbox)`. If `radio` was assigned, there will be a radio button in the selection column; otherwise, the `checkbox` instead.
#### values #### values
* `radio` * **radio**
* `checkbox` * **checkbox**
#### examples #### examples
@@ -35,6 +30,7 @@ Specifying the selection way for `single(radio)` or `multiple(checkbox)`. If `ra
const selectRow = { const selectRow = {
mode: 'radio' // single row selection mode: 'radio' // single row selection
}; };
<BootstrapTable <BootstrapTable
keyField='id' keyField='id'
data={ products } data={ products }
@@ -56,7 +52,7 @@ const selectRow = {
/> />
``` ```
## <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:
```js ```js
@@ -75,7 +71,7 @@ const selectRow = {
}; };
``` ```
## <a name='classes'>selectRow.classes - [String | Function]</a> ### <a name='classes'>selectRow.classes - [String | Function]</a>
`selectRow.classes` allow you to add css class on selected rows: `selectRow.classes` allow you to add css class on selected rows:
```js ```js
@@ -94,7 +90,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 backgroud color when row is selected
```js ```js
@@ -115,7 +111,7 @@ const selectRow = {
}; };
``` ```
## <a name='nonSelectable'>selectRow.nonSelectable - [Array]</a> ### <a name='nonSelectable'>selectRow.nonSelectable - [Array]</a>
This prop allow you to restrict some rows which can not be selected by user. `selectRow.nonSelectable` accept an rowkeys array. This prop allow you to restrict some rows which can not be selected by user. `selectRow.nonSelectable` accept an rowkeys array.
```js ```js
@@ -125,8 +121,8 @@ const selectRow = {
}; };
``` ```
## <a name='clickToSelect'>selectRow.clickToSelect - [Bool]</a> ### <a name='clickToSelect'>selectRow.clickToSelect - [Bool]</a>
Able to select row when clicking on row. Allow user to select row by clicking on the row.
```js ```js
const selectRow = { const selectRow = {
@@ -135,10 +131,10 @@ const selectRow = {
}; };
``` ```
> Note: if you also enable [cellEdit](./cell-edit.md), the `selectRow.clickToSelect` will deactivate the functionality of cell editing > Note: When you also enable [cellEdit](./cell-edit.md), the `selectRow.clickToSelect` will deactivate the functionality of cell editing
> If you want to click on row to select row and edit cell simultaneously, you are suppose to enable [`selectRow.clickToEdit`](#clickToEdit) > If you want to click on row to select row and edit cell simultaneously, you are suppose to enable [`selectRow.clickToEdit`](#clickToEdit)
## <a name='clickToEdit'>selectRow.clickToEdit - [Bool]</a> ### <a name='clickToEdit'>selectRow.clickToEdit - [Bool]</a>
Able to click to edit cell and select row Able to click to edit cell and select row
```js ```js
@@ -149,7 +145,7 @@ const selectRow = {
}; };
``` ```
## <a name='onSelect'>selectRow.onSelect - [Function]</a> ### <a name='onSelect'>selectRow.onSelect - [Function]</a>
This callback function will be called when a row is select/unselect and pass following three arguments: This callback function will be called when a row is select/unselect and pass following three arguments:
`row`, `isSelect` and `rowIndex`. `row`, `isSelect` and `rowIndex`.
@@ -162,7 +158,7 @@ const selectRow = {
}; };
``` ```
## <a name='onSelectAll'>selectRow.onSelectAll - [Function]</a> ### <a name='onSelectAll'>selectRow.onSelectAll - [Function]</a>
This callback function will be called when select/unselect all and it only work when you configure [`selectRow.mode`](#mode) as `checkbox`. This callback function will be called when select/unselect all and it only work when you configure [`selectRow.mode`](#mode) as `checkbox`.
```js ```js
@@ -174,7 +170,7 @@ const selectRow = {
}; };
``` ```
## <a name='hideSelectColumn'>selectRow.hideSelectColumn - [Bool]</a> ### <a name='hideSelectColumn'>selectRow.hideSelectColumn - [Bool]</a>
Default is `false`, if you don't want to have a selection column, give this prop as `true` Default is `false`, if you don't want to have a selection column, give this prop as `true`
```js ```js

84
gulpfile.babel.js Normal file
View File

@@ -0,0 +1,84 @@
import gulp from 'gulp';
import babel from 'gulp-babel';
import sass from 'gulp-sass';
import cleanCSS from 'gulp-clean-css';
import cleanDir from 'gulp-clean';
import rename from 'gulp-rename';
import shell from 'gulp-shell';
const LIB = 'lib';
const DIST = 'dist';
const TEST = 'test';
const PKG_PATH = './packages';
const NODE_MODULES = 'node_modules';
const JS_PKGS = [
'react-bootstrap-table2',
'react-bootstrap-table2-editor',
'react-bootstrap-table2-filter',
'react-bootstrap-table2-overlay',
'react-bootstrap-table2-paginator'
].reduce((pkg, curr) => `${curr}|${pkg}`, '');
const JS_SKIPS = `+(${TEST}|${LIB}|${DIST}|${NODE_MODULES})`;
const STYLE_PKGS = [
'react-bootstrap-table2',
'react-bootstrap-table2-paginator'
].reduce((pkg, curr) => `${curr}|${pkg}`, '');
const STYLE_SKIPS = `+(${NODE_MODULES})`;
function clean() {
return gulp
.src(`./packages/+(${JS_PKGS})/+(${LIB}|${DIST})`, { allowEmpty: true })
.pipe(cleanDir());
}
function scripts() {
return gulp
.src([
`./packages/+(${JS_PKGS})/**/*.js`,
`!packages/+(${JS_PKGS})/${JS_SKIPS}/**/*.js`
])
.pipe(babel())
.pipe(rename((path) => {
if (path.dirname.indexOf('src') > -1) {
path.dirname = path.dirname.replace('src', `${LIB}/src`);
} else {
path.dirname += `/${LIB}`;
}
}))
.pipe(gulp.dest(PKG_PATH));
}
function styles() {
return gulp
.src([
`./packages/+(${STYLE_PKGS})/style/**/*.scss`,
`!packages/+(${STYLE_PKGS})/${STYLE_SKIPS}/**/*.scss`
])
.pipe(sass().on('error', sass.logError))
.pipe(rename((path) => {
path.dirname = path.dirname.replace('style', DIST);
}))
.pipe(gulp.dest(PKG_PATH))
.pipe(cleanCSS({ compatibility: 'ie8' }))
.pipe(rename((path) => {
path.extname = '.min.css';
}))
.pipe(gulp.dest(PKG_PATH));
}
function umd() {
return gulp.src('./webpack.prod.config.babel.js')
.pipe(shell(['webpack --config <%= file.path %>']));
}
const buildJS = gulp.parallel(umd, scripts);
const buildCSS = styles;
const build = gulp.series(clean, gulp.parallel(buildJS, buildCSS));
gulp.task('prod', build);
gulp.task('default', build);

View File

@@ -3,5 +3,5 @@
"packages": [ "packages": [
"packages/*" "packages/*"
], ],
"version": "0.0.0" "version": "independent"
} }

View File

@@ -5,25 +5,33 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"postinstall": "lerna bootstrap", "postinstall": "lerna bootstrap",
"start": "node -r babel-register ./node_modules/.bin/webpack-dev-server --config webpack.config.babel.js", "build": "./node_modules/.bin/gulp prod",
"lint": "eslint ./packages --ext .js --ext .jsx --ignore-path .gitignore", "lint": "eslint ./packages --ext .js --ext .jsx --ignore-path .gitignore",
"pretest": "yarn lint --cache", "pretest": "yarn lint --cache",
"test": "jest", "test": "jest",
"test:coverage": "jest --coverage", "test:coverage": "jest --coverage",
"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:build": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:build"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git" "url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git"
}, },
"author": "", "author": "AllenFang",
"license": "ISC", "contributors": [{
"name": "Chun-MingChen",
"email": "nick830314@gmail.com",
"url": "https://github.com/Chun-MingChen"
}],
"license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/react-bootstrap-table/react-bootstrap-table2/issues" "url": "https://github.com/react-bootstrap-table/react-bootstrap-table2/issues"
}, },
"homepage": "https://github.com/react-bootstrap-table/react-bootstrap-table2#readme", "homepage": "https://github.com/react-bootstrap-table/react-bootstrap-table2#readme",
"devDependencies": { "devDependencies": {
"babel-cli": "6.26.0",
"babel-core": "6.25.0", "babel-core": "6.25.0",
"babel-eslint": "7.2.3", "babel-eslint": "7.2.3",
"babel-jest": "20.0.3", "babel-jest": "20.0.3",
@@ -41,6 +49,13 @@
"eslint-plugin-import": "2.7.0", "eslint-plugin-import": "2.7.0",
"eslint-plugin-jsx-a11y": "5.1.1", "eslint-plugin-jsx-a11y": "5.1.1",
"eslint-plugin-react": "7.2.1", "eslint-plugin-react": "7.2.1",
"gulp": "4.0.0",
"gulp-babel": "7.0.0",
"gulp-clean": "0.4.0",
"gulp-clean-css": "3.9.2",
"gulp-rename": "^1.2.2",
"gulp-sass": "3.1.0",
"gulp-shell": "0.6.5",
"html-webpack-plugin": "2.30.1", "html-webpack-plugin": "2.30.1",
"jest": "20.0.4", "jest": "20.0.4",
"jsdom": "11.2.0", "jsdom": "11.2.0",
@@ -60,11 +75,6 @@
"react": "16.0.0", "react": "16.0.0",
"react-dom": "16.0.0" "react-dom": "16.0.0"
}, },
"peerDependencies": {
"prop-types": "^15.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0"
},
"jest": { "jest": {
"collectCoverageFrom": [ "collectCoverageFrom": [
"packages/**/*.js" "packages/**/*.js"

View File

@@ -0,0 +1,59 @@
# react-bootstrap-table2-editor
`react-bootstrap-table2` separate the cell edit code base to [`react-bootstrap-table2-editor`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-editor), so there's a little bit different when you use cell edit than `react-bootstrap-table`. In the following, we are going to show you how to enable the cell edit
**[Live Demo For Cell Edit](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Cell%20Editing)**
-----
## Install
```sh
$ npm install react-bootstrap-table2-editor --save
```
## How
We have [two ways](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html#celleditmode-string) to trigger a editable cell as editing cell:
* click
* dbclick
That's look into how we enable the cell edit on tabe:
```js
import cellEditFactory from 'react-bootstrap-table2-editor';
// omit
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
```
How user save their new editings? We offer two ways:
* Press ENTER(**default**)
* Blur from current editing cell(Need to enable the [cellEdit.blurToSave](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html#celleditblurtosave-bool))
## Editable Cell
`react-bootstrap-table2` support you to configure the cell editable on three level:
* Row Level ([cellEdit.nonEditableRows](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html#celleditnoneditablerows-function))
* 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)
## Customize Style/Class
Currently, we only support the editing cell style/class customization, in the future, we will offer more customizations.
### 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 classname via [column.editCellClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellclasses-string-function)
## Validation
[`column.validator`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will help you to work on it!

View File

@@ -0,0 +1,16 @@
import wrapperFactory from './src/wrapper';
import editingCellFactory from './src/editing-cell';
import {
CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK
} from './src/const';
export default (options = {}) => ({
wrapperFactory,
editingCellFactory,
CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK,
options
});

View File

@@ -0,0 +1,42 @@
{
"name": "react-bootstrap-table2-editor",
"version": "0.0.3",
"description": "it's the editor addon for react-bootstrap-table2",
"main": "./lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git"
},
"keywords": [
"react",
"bootstrap",
"table",
"grid",
"react-bootstrap-table-addons",
"react-component"
],
"files": [
"lib/",
"dist/"
],
"tags": [
"react"
],
"author": "AllenFang",
"contributors": [
{
"name": "Chun-MingChen",
"email": "nick830314@gmail.com",
"url": "https://github.com/Chun-MingChen"
}
],
"peerDependencies": {
"prop-types": "^15.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0"
}
}

View File

@@ -0,0 +1,4 @@
export const TIME_TO_CLOSE_MESSAGE = 3000;
export const DELAY_FOR_DBCLICK = 200;
export const CLICK_TO_CELL_EDIT = 'click';
export const DBCLICK_TO_CELL_EDIT = 'dbclick';

View File

@@ -0,0 +1,153 @@
/* eslint react/prop-types: 0 */
/* eslint no-return-assign: 0 */
/* eslint class-methods-use-this: 0 */
/* eslint jsx-a11y/no-noninteractive-element-interactions: 0 */
import React, { Component } from 'react';
import cs from 'classnames';
import PropTypes from 'prop-types';
import TextEditor from './text-editor';
import EditorIndicator from './editor-indicator';
import { TIME_TO_CLOSE_MESSAGE } from './const';
export default _ =>
class EditingCell extends Component {
static propTypes = {
row: PropTypes.object.isRequired,
column: PropTypes.object.isRequired,
onUpdate: PropTypes.func.isRequired,
onEscape: PropTypes.func.isRequired,
timeToCloseMessage: PropTypes.number,
className: PropTypes.string,
style: PropTypes.object
}
static defaultProps = {
timeToCloseMessage: TIME_TO_CLOSE_MESSAGE,
className: null,
style: {}
}
constructor(props) {
super(props);
this.indicatorTimer = null;
this.clearTimer = this.clearTimer.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.beforeComplete = this.beforeComplete.bind(this);
this.state = {
invalidMessage: null
};
}
componentWillReceiveProps({ message }) {
if (_.isDefined(message)) {
this.createTimer();
this.setState(() => ({
invalidMessage: message
}));
}
}
componentWillUnmount() {
this.clearTimer();
}
clearTimer() {
if (this.indicatorTimer) {
clearTimeout(this.indicatorTimer);
}
}
createTimer() {
this.clearTimer();
const { timeToCloseMessage, onErrorMessageDisappear } = this.props;
this.indicatorTimer = _.sleep(() => {
this.setState(() => ({
invalidMessage: null
}));
if (_.isFunction(onErrorMessageDisappear)) onErrorMessageDisappear();
}, timeToCloseMessage);
}
beforeComplete(row, column, newValue) {
const { onUpdate } = this.props;
if (_.isFunction(column.validator)) {
const validateForm = column.validator(newValue, row, column);
if (_.isObject(validateForm) && !validateForm.valid) {
this.setState(() => ({
invalidMessage: validateForm.message
}));
this.createTimer();
return;
}
}
onUpdate(row, column, newValue);
}
handleBlur() {
const { onEscape, blurToSave, row, column } = this.props;
if (blurToSave) {
const value = this.editor.text.value;
if (!_.isDefined(value)) {
// TODO: for other custom or embed editor
}
this.beforeComplete(row, column, value);
} else {
onEscape();
}
}
handleKeyDown(e) {
const { onEscape, row, column } = this.props;
if (e.keyCode === 27) { // ESC
onEscape();
} else if (e.keyCode === 13) { // ENTER
const value = e.currentTarget.value;
if (!_.isDefined(value)) {
// TODO: for other custom or embed editor
}
this.beforeComplete(row, column, value);
}
}
handleClick(e) {
if (e.target.tagName !== 'TD') {
// To avoid the row selection event be triggered,
// When user define selectRow.clickToSelect and selectRow.clickToEdit
// We shouldn't trigger selection event even if user click on the cell editor(input)
e.stopPropagation();
}
}
render() {
const { invalidMessage } = this.state;
const { row, column, className, style } = this.props;
const { dataField } = column;
const value = _.get(row, dataField);
const editorAttrs = {
onKeyDown: this.handleKeyDown,
onBlur: this.handleBlur
};
const hasError = _.isDefined(invalidMessage);
const editorClass = hasError ? cs('animated', 'shake') : null;
return (
<td
className={ cs('react-bootstrap-table-editing-cell', className) }
style={ style }
onClick={ this.handleClick }
>
<TextEditor
ref={ node => this.editor = node }
defaultValue={ value }
className={ editorClass }
{ ...editorAttrs }
/>
{ hasError ? <EditorIndicator invalidMessage={ invalidMessage } /> : null }
</td>
);
}
};

View File

@@ -0,0 +1,135 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from './const';
export default (
Base,
{ _, remoteResolver }
) => {
let EditingCell;
return class CellEditWrapper extends remoteResolver(Component) {
static propTypes = {
options: PropTypes.shape({
mode: PropTypes.oneOf([CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT]).isRequired,
onErrorMessageDisappear: PropTypes.func,
blurToSave: PropTypes.bool,
beforeSaveCell: PropTypes.func,
afterSaveCell: PropTypes.func,
nonEditableRows: PropTypes.func,
timeToCloseMessage: PropTypes.number,
errorMessage: PropTypes.string
})
}
constructor(props) {
super(props);
EditingCell = props.cellEdit.editingCellFactory(_);
this.startEditing = this.startEditing.bind(this);
this.escapeEditing = this.escapeEditing.bind(this);
this.completeEditing = this.completeEditing.bind(this);
this.handleCellUpdate = this.handleCellUpdate.bind(this);
this.state = {
ridx: null,
cidx: null,
message: null,
isDataChanged: false
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.cellEdit && this.isRemoteCellEdit()) {
if (nextProps.cellEdit.options.errorMessage) {
this.setState(() => ({
isDataChanged: false,
message: nextProps.cellEdit.options.errorMessage
}));
} else {
this.setState(() => ({
isDataChanged: true
}));
this.escapeEditing();
}
} else {
this.setState(() => ({
isDataChanged: false
}));
}
}
handleCellUpdate(row, column, newValue) {
const { keyField, cellEdit, store } = this.props;
const { beforeSaveCell, afterSaveCell } = cellEdit.options;
const oldValue = _.get(row, column.dataField);
const rowId = _.get(row, keyField);
if (_.isFunction(beforeSaveCell)) beforeSaveCell(oldValue, newValue, row, column);
if (this.isRemoteCellEdit()) {
this.handleCellChange(rowId, column.dataField, newValue);
} else {
store.edit(rowId, column.dataField, newValue);
if (_.isFunction(afterSaveCell)) afterSaveCell(oldValue, newValue, row, column);
this.completeEditing();
}
}
completeEditing() {
this.setState(() => ({
ridx: null,
cidx: null,
message: null,
isDataChanged: true
}));
}
startEditing(ridx, cidx) {
const editing = () => {
this.setState(() => ({
ridx,
cidx,
isDataChanged: false
}));
};
const { selectRow } = this.props;
if (!selectRow || (selectRow.clickToEdit || !selectRow.clickToSelect)) editing();
}
escapeEditing() {
this.setState(() => ({
ridx: null,
cidx: null
}));
}
render() {
const { isDataChanged, ...stateRest } = this.state;
const {
cellEdit: {
options: { nonEditableRows, errorMessage, ...optionsRest },
editingCellFactory,
...cellEditRest
}
} = this.props;
const newCellEdit = {
...optionsRest,
...cellEditRest,
...stateRest,
EditingCell,
nonEditableRows: _.isDefined(nonEditableRows) ? nonEditableRows() : [],
onStart: this.startEditing,
onEscape: this.escapeEditing,
onUpdate: this.handleCellUpdate
};
return (
<Base
{ ...this.props }
data={ this.props.store.data }
isDataChanged={ isDataChanged }
cellEdit={ newCellEdit }
/>
);
}
};
};

View File

@@ -1,12 +1,23 @@
/* eslint react/prop-types: 0 */
import 'jsdom-global/register'; import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import sinon from 'sinon'; import sinon from 'sinon';
import { shallow, mount } from 'enzyme'; import { shallow, mount } from 'enzyme';
import { TableRowWrapper } from '../test-helpers/table-wrapper'; import _ from 'react-bootstrap-table-next/src/utils';
import EditingCell from '../../src/cell-edit/editing-cell'; import editingCellFactory from '../src/editing-cell';
import TextEditor from '../../src/cell-edit/text-editor'; import TextEditor from '../src/text-editor';
import EditorIndicator from '../../src/cell-edit/editor-indicator'; import EditorIndicator from '../src/editor-indicator';
const EditingCell = editingCellFactory(_);
const TableRowWrapper = props => (
<table>
<tbody>
<tr>{ props.children }</tr>
</tbody>
</table>
);
describe('EditingCell', () => { describe('EditingCell', () => {
let wrapper; let wrapper;

View File

@@ -2,7 +2,7 @@ import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import TextEditor from '../../src/cell-edit/text-editor'; import TextEditor from '../src/text-editor';
describe('TextEditor', () => { describe('TextEditor', () => {
let wrapper; let wrapper;

View File

@@ -0,0 +1,330 @@
import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils';
import remoteResolver from 'react-bootstrap-table-next/src/props-resolver/remote-resolver';
import Store from 'react-bootstrap-table-next/src/store';
import BootstrapTable from 'react-bootstrap-table-next/src/bootstrap-table';
import cellEditFactory from '..';
import * as Const from '../src/const';
import wrapperFactory from '../src/wrapper';
describe('CellEditWrapper', () => {
let wrapper;
let instance;
const onTableChangeCB = sinon.stub();
const columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}];
const createTableProps = (props = {}) => {
const { cellEdit, ...rest } = props;
const tableProps = {
keyField: 'id',
columns,
data,
_,
store: new Store('id'),
cellEdit: cellEditFactory(cellEdit),
onTableChange: onTableChangeCB,
...rest
};
tableProps.store.data = data;
return tableProps;
};
const CellEditWrapper = wrapperFactory(BootstrapTable, {
_,
remoteResolver
});
const createCellEditWrapper = (props, renderFragment = true) => {
wrapper = shallow(<CellEditWrapper { ...props } />);
instance = wrapper.instance();
if (renderFragment) {
const fragment = instance.render();
wrapper = shallow(<div>{ fragment }</div>);
}
};
afterEach(() => {
onTableChangeCB.reset();
});
beforeEach(() => {
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT }
});
createCellEditWrapper(props);
});
it('should render CellEditWrapper correctly', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(BootstrapTable)).toBeDefined();
});
it('should have correct state', () => {
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeNull();
expect(instance.state.message).toBeNull();
expect(instance.state.isDataChanged).toBeFalsy();
});
it('should inject correct props to base component', () => {
const base = wrapper.find(BootstrapTable);
expect(base.props().cellEdit).toBeDefined();
expect(base.props().cellEdit.onStart).toBeDefined();
expect(base.props().cellEdit.onEscape).toBeDefined();
expect(base.props().cellEdit.onUpdate).toBeDefined();
expect(base.props().cellEdit.EditingCell).toBeDefined();
expect(base.props().cellEdit.ridx).toBeNull();
expect(base.props().cellEdit.cidx).toBeNull();
expect(base.props().cellEdit.message).toBeNull();
expect(base.props().isDataChanged).toBe(instance.state.isDataChanged);
});
describe('when receive new cellEdit prop', () => {
const spy = jest.spyOn(CellEditWrapper.prototype, 'escapeEditing');
describe('and cellEdit is not work on remote', () => {
beforeEach(() => {
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT }
});
createCellEditWrapper(props);
wrapper.setProps({ cellEdit: props.cellEdit });
});
it('should always setting state.isDataChanged as false', () => {
expect(instance.state.isDataChanged).toBeFalsy();
});
});
describe('and cellEdit is work on remote', () => {
let errorMessage;
let props;
beforeEach(() => {
props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
remote: true
});
});
describe('and cellEdit.errorMessage is defined', () => {
beforeEach(() => {
createCellEditWrapper(props, false);
errorMessage = 'test';
const newCellEdit = {
...props.cellEdit,
options: { ...props.cellEdit.options, errorMessage }
};
wrapper.setProps({ cellEdit: newCellEdit });
});
it('should setting correct state', () => {
expect(instance.state.isDataChanged).toBeFalsy();
expect(instance.state.message).toEqual(errorMessage);
});
});
describe('and cellEdit.errorMessage is undefined', () => {
beforeEach(() => {
errorMessage = null;
createCellEditWrapper(props, false);
const newCellEdit = {
...props.cellEdit,
options: { ...props.cellEdit.options, errorMessage }
};
wrapper.setProps({ cellEdit: newCellEdit });
});
it('should setting correct state', () => {
expect(wrapper.state().isDataChanged).toBeTruthy();
});
it('should escape current editing', () => {
expect(spy).toHaveBeenCalled();
});
});
});
});
describe('call escapeEditing function', () => {
it('should set state correctly', () => {
instance.escapeEditing();
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeNull();
});
});
describe('call startEditing function', () => {
const ridx = 1;
const cidx = 3;
it('should set state correctly', () => {
instance.startEditing(ridx, cidx);
expect(instance.state.ridx).toEqual(ridx);
expect(instance.state.cidx).toEqual(cidx);
expect(instance.state.isDataChanged).toBeFalsy();
});
describe('if selectRow.clickToSelect is defined', () => {
beforeEach(() => {
const selectRow = { mode: 'checkbox', clickToSelect: true };
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
selectRow
});
createCellEditWrapper(props);
});
it('should not set state', () => {
instance.startEditing(ridx, cidx);
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeDefined();
});
});
describe('if selectRow.clickToSelect and selectRow.clickToEdit is defined', () => {
beforeEach(() => {
const selectRow = { mode: 'checkbox', clickToSelect: true, clickToEdit: true };
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
selectRow
});
createCellEditWrapper(props);
});
it('should set state correctly', () => {
instance.startEditing(ridx, cidx);
expect(instance.state.ridx).toEqual(ridx);
expect(instance.state.cidx).toEqual(cidx);
});
});
});
describe('call completeEditing function', () => {
it('should set state correctly', () => {
instance.completeEditing();
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeNull();
expect(instance.state.message).toBeNull();
expect(instance.state.isDataChanged).toBeTruthy();
});
});
describe('call handleCellUpdate function', () => {
let props;
const row = data[0];
const column = columns[1];
const newValue = 'new name';
describe('when cell edit is work on remote', () => {
const spy = jest.spyOn(CellEditWrapper.prototype, 'handleCellChange');
beforeEach(() => {
props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
remote: true
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
it('should calling handleCellChange correctly', () => {
expect(spy).toHaveBeenCalled();
expect(spy.mock.calls).toHaveLength(1);
expect(spy.mock.calls[0]).toHaveLength(3);
expect(spy.mock.calls[0][0]).toEqual(row.id);
expect(spy.mock.calls[0][1]).toEqual(column.dataField);
expect(spy.mock.calls[0][2]).toEqual(newValue);
});
});
describe('when cell edit is not work on remote', () => {
const spyOnCompleteEditing = jest.spyOn(CellEditWrapper.prototype, 'completeEditing');
const spyOnStoreEdit = jest.spyOn(Store.prototype, 'edit');
beforeEach(() => {
props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT }
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
afterEach(() => {
spyOnStoreEdit.mockReset();
spyOnCompleteEditing.mockReset();
});
it('should calling props.store.edit', () => {
expect(spyOnStoreEdit).toHaveBeenCalled();
expect(spyOnStoreEdit.mock.calls).toHaveLength(1);
expect(spyOnStoreEdit.mock.calls[0]).toHaveLength(3);
expect(spyOnStoreEdit.mock.calls[0][0]).toEqual(row.id);
expect(spyOnStoreEdit.mock.calls[0][1]).toEqual(column.dataField);
expect(spyOnStoreEdit.mock.calls[0][2]).toEqual(newValue);
});
it('should calling completeEditing function', () => {
expect(spyOnCompleteEditing).toHaveBeenCalled();
});
describe('if cellEdit.afterSaveCell prop defined', () => {
const aftereSaveCellCallBack = sinon.stub();
beforeEach(() => {
props = createTableProps({
cellEdit: {
mode: Const.CLICK_TO_CELL_EDIT,
afterSaveCell: aftereSaveCellCallBack
}
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
it('should calling cellEdit.afterSaveCell correctly', () => {
expect(aftereSaveCellCallBack.callCount).toBe(1);
expect(aftereSaveCellCallBack.calledWith(
row[column.dataField], newValue, row, column)
).toBe(true);
});
});
});
describe('if cellEdit.beforeSaveCell prop defined', () => {
const beforeSaveCellCallBack = sinon.stub();
beforeEach(() => {
props = createTableProps({
cellEdit: {
mode: Const.CLICK_TO_CELL_EDIT,
beforeSaveCell: beforeSaveCellCallBack
}
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
it('should calling cellEdit.beforeSaveCell correctly', () => {
expect(beforeSaveCellCallBack.callCount).toBe(1);
expect(beforeSaveCellCallBack.calledWith(
row[column.dataField], newValue, row, column)
).toBe(true);
});
});
});
});

View File

@@ -0,0 +1,3 @@
{
"presets": ["react", "es2015", "stage-0", ["env", {"modules": false} ]]
}

View File

@@ -1,9 +1,10 @@
const path = require('path'); const path = require('path');
const sourcePath = path.join(__dirname, '../../react-bootstrap-table2/src'); const sourcePath = path.join(__dirname, '../../react-bootstrap-table2');
const paginationSourcePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/src'); const paginationSourcePath = path.join(__dirname, '../../react-bootstrap-table2-paginator');
const overlaySourcePath = path.join(__dirname, '../../react-bootstrap-table2-overlay/src'); const overlaySourcePath = path.join(__dirname, '../../react-bootstrap-table2-overlay');
const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filter/src'); const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filter');
const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor');
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 storyPath = path.join(__dirname, '../stories'); const storyPath = path.join(__dirname, '../stories');
@@ -15,6 +16,12 @@ const aliasPath = {
src: srcPath, src: srcPath,
components: path.join(srcPath, 'components'), components: path.join(srcPath, 'components'),
utils: path.join(srcPath, 'utils'), utils: path.join(srcPath, 'utils'),
'react-bootstrap-table-next': sourcePath,
'react-bootstrap-table2-editor': editorSourcePath,
'react-bootstrap-table2-filter': filterSourcePath,
'react-bootstrap-table2-overlay': overlaySourcePath,
'react-bootstrap-table2-paginator': paginationSourcePath,
}; };
const loaders = [{ const loaders = [{
@@ -27,7 +34,7 @@ const loaders = [{
test: /\.js?$/, test: /\.js?$/,
use: ['babel-loader'], use: ['babel-loader'],
exclude: /node_modules/, exclude: /node_modules/,
include: [sourcePath, paginationSourcePath, overlaySourcePath, filterSourcePath, storyPath], include: [sourcePath, paginationSourcePath, overlaySourcePath, filterSourcePath, editorSourcePath, storyPath]
}, { }, {
test: /\.css$/, test: /\.css$/,
use: ['style-loader', 'css-loader'], use: ['style-loader', 'css-loader'],

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
const columns = [{ const columns = [{

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -18,6 +19,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -29,26 +32,28 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const cellEdit = {
mode: 'click',
blurToSave: true
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/> />
`; `;
const cellEdit = {
mode: 'click',
blurToSave: true
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,7 +1,8 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -22,6 +23,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -36,24 +39,22 @@ const columns = [{
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101') (cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
}]; }];
const cellEdit = {
mode: 'click'
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({ mode: 'click' }) }
/> />
`; `;
const cellEdit = {
mode: 'click'
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -2,7 +2,8 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -20,6 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -31,28 +34,30 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const cellEdit = {
mode: 'click',
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({
mode: 'click',
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
}) }
/> />
`; `;
const cellEdit = {
mode: 'click',
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
}) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,7 +1,8 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -26,6 +27,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -44,24 +47,22 @@ const columns = [{
} }
}]; }];
const cellEdit = {
mode: 'click'
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({ mode: 'click' }) }
/> />
`; `;
const cellEdit = {
mode: 'click'
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,6 +1,7 @@
import React from 'react';
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import BootstrapTable from 'react-bootstrap-table2'; 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 Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -33,6 +34,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -59,27 +62,29 @@ const columns = [{
} }
}]; }];
const cellEdit = {
mode: 'click',
blurToSave: true
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/> />
`; `;
const cellEdit = {
mode: 'click',
blurToSave: true
};
export default () => ( export default () => (
<div> <div>
<h3>Product Price should bigger than $2000</h3> <h3>Product Price should bigger than $2000</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,75 +0,0 @@
/* eslint no-unused-vars: 0 */
/* eslint arrow-body-style: 0 */
import React, { Component } from 'react';
import BootstrapTable from 'react-bootstrap-table2';
import Code from 'components/common/code-block';
import { productsGenerator, sleep } 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 = `\
class CellEditWithPromise extends Component {
handleCellEditing = (rowId, dataField, newValue) => {
return sleep(1000).then(() => {
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
throw new Error('Product Price should bigger than $2000');
}
});
}
render() {
const cellEdit = {
mode: 'click',
blurToSave: true,
onUpdate: this.handleCellEditing
};
return (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
<Code>{ sourceCode }</Code>
</div>
);
}
}
`;
class CellEditWithPromise extends Component {
handleCellEditing = (rowId, dataField, newValue) => {
return sleep(1000).then(() => {
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
throw new Error('Product Price should bigger than $2000');
}
});
}
render() {
const cellEdit = {
mode: 'click',
blurToSave: true,
onUpdate: this.handleCellEditing
};
return (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
<Code>{ sourceCode }</Code>
</div>
);
}
}
export default CellEditWithPromise;

View File

@@ -1,212 +0,0 @@
/* eslint no-unused-vars: 0 */
/* eslint react/prop-types: 0 */
/* eslint arrow-body-style: 0 */
/* eslint consistent-return: 0 */
/* eslint no-class-assign: 0 */
import React, { Component } from 'react';
import thunk from 'redux-thunk';
import { Provider, connect } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import BootstrapTable from 'react-bootstrap-table2';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
/////////////////////// Action Creator ///////////////////////
const setErrorMessage = (errorMessage = null) => {
return { type: 'SET_ERR_MESSAGE', errorMessage };
};
// Async Action, using redux-thunk
const cellEditingAsync = (rowId, dataField, newValue) => {
return (dispatch) => {
setTimeout(() => {
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
dispatch(setErrorMessage('Product Price should bigger than $2000'));
} else {
dispatch({ type: 'ADD_SUCCESS', rowId, dataField, newValue });
}
}, 1200);
};
};
/////////////////////// Component ///////////////////////
class CellEditWithRedux extends Component {
// dispatch a async action
handleCellEditing = (rowId, dataField, newValue) => {
this.props.dispatch(cellEditingAsync(rowId, dataField, newValue));
return false;
}
handleErrorMsgDisappear = () => {
this.props.dispatch(setErrorMessage());
}
render() {
const cellEdit = {
mode: 'click',
editing: this.props.cellEditing,
errorMessage: this.props.errorMessage,
onUpdate: this.handleCellEditing,
onErrorMessageDisappear: this.handleErrorMsgDisappear
};
return (
<div>
<BootstrapTable keyField="id" data={ this.props.data } columns={ columns } cellEdit={ cellEdit } />
<Code>{ sourceCode }</Code>
</div>
);
}
}
// connect
CellEditWithRedux = connect(state => state)(CellEditWithRedux);
/////////////////////// Reducer ///////////////////////
// initial state object and simple reducers
const initialState = {
data: productsGenerator(),
cellEditing: false,
errorMessage: null
};
const reducers = (state, action) => {
switch (action.type) {
case 'ADD_SUCCESS': {
const { rowId, dataField, newValue } = action;
const data = [...state.data];
const rowIndex = data.findIndex(r => r.id === rowId);
data[rowIndex][dataField] = newValue;
return {
data,
cellEditing: false,
errorMessage: null
};
}
case 'SET_ERR_MESSAGE': {
const { errorMessage } = action;
return {
...state,
cellEditing: true,
errorMessage
};
}
default: {
return { ...state };
}
}
};
/////////////////////// Index ///////////////////////
const store = createStore(reducers, initialState, applyMiddleware(thunk));
const Index = () => (
<Provider store={store}>
<CellEditWithRedux />
</Provider>
);
`;
const setErrorMessage = (errorMessage = null) => {
return { type: 'SET_ERR_MESSAGE', errorMessage };
};
// Async Action, using redux-thunk
const cellEditingAsync = (rowId, dataField, newValue) => {
return (dispatch) => {
setTimeout(() => {
if (dataField === 'price' && (newValue < 2000 || isNaN(newValue))) {
dispatch(setErrorMessage('Product Price should bigger than $2000'));
} else {
dispatch({ type: 'ADD_SUCCESS', rowId, dataField, newValue });
}
}, 1200);
};
};
class CellEditWithRedux extends Component {
// dispatch a async action
handleCellEditing = (rowId, dataField, newValue) => {
this.props.dispatch(cellEditingAsync(rowId, dataField, newValue));
return false;
}
handleErrorMsgDisappear = () => {
this.props.dispatch(setErrorMessage());
}
render() {
const cellEdit = {
mode: 'click',
editing: this.props.cellEditing,
errorMessage: this.props.errorMessage,
onUpdate: this.handleCellEditing,
onErrorMessageDisappear: this.handleErrorMsgDisappear
};
return (
<div>
<BootstrapTable keyField="id" data={ this.props.data } columns={ columns } cellEdit={ cellEdit } />
<Code>{ sourceCode }</Code>
</div>
);
}
}
// connect
CellEditWithRedux = connect(state => state)(CellEditWithRedux);
// initial state object and simple reducers
const initialState = {
data: productsGenerator(),
cellEditing: false,
errorMessage: null
};
const reducers = (state, action) => {
switch (action.type) {
case 'ADD_SUCCESS': {
const { rowId, dataField, newValue } = action;
const data = JSON.parse(JSON.stringify(state.data));
const rowIndex = data.findIndex(r => r.id === rowId);
data[rowIndex][dataField] = newValue;
return {
data,
cellEditing: false,
errorMessage: null
};
}
case 'SET_ERR_MESSAGE': {
const { errorMessage } = action;
return {
...state,
cellEditing: true,
errorMessage
};
}
default: {
return { ...state };
}
}
};
const store = createStore(reducers, initialState, applyMiddleware(thunk));
const Index = () => (
<Provider store={ store }>
<CellEditWithRedux />
</Provider>
);
export default Index;

View File

@@ -1,7 +1,8 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -20,6 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -32,24 +35,22 @@ const columns = [{
editable: (content, row, rowIndex, columnIndex) => content > 2101 editable: (content, row, rowIndex, columnIndex) => content > 2101
}]; }];
const cellEdit = {
mode: 'click'
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({ mode: 'click' }) }
/> />
`; `;
const cellEdit = {
mode: 'click'
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,6 +1,8 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -18,6 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -29,24 +33,22 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const cellEdit = {
mode: 'click'
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({ mode: 'click' }) }
/> />
`; `;
const cellEdit = {
mode: 'click'
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -19,6 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -32,26 +35,28 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const cellEdit = {
mode: 'click',
blurToSave: true
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/> />
`; `;
const cellEdit = {
mode: 'click',
blurToSave: true
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -18,6 +19,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -29,24 +32,22 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const cellEdit = {
mode: 'dbclick'
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({ mode: 'dbclick' }) }
/> />
`; `;
const cellEdit = {
mode: 'dbclick'
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'dbclick' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -18,6 +19,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -29,29 +32,29 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const cellEdit = {
mode: 'click',
blurToSave: true,
// Product ID: 0, 3 will be non-editable
nonEditableRows: () => [0, 3]
};
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
cellEdit={ cellEdit } cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true,
nonEditableRows: () => [0, 3]
}) }
/> />
`; `;
const cellEdit = {
mode: 'click',
blurToSave: true,
nonEditableRows: () => [0, 3]
};
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true,
nonEditableRows: () => [0, 3]
}) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,6 +1,6 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { jobsGenerator } from 'utils/common'; import { jobsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -2,7 +2,7 @@
/* eslint no-alert: 0 */ /* eslint no-alert: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -2,7 +2,7 @@
/* eslint no-alert: 0 */ /* eslint no-alert: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -2,7 +2,7 @@
/* eslint react/prefer-stateless-function: 0 */ /* eslint react/prefer-stateless-function: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,8 +1,8 @@
/* eslint react/no-multi-comp: 0 */ /* eslint react/no-multi-comp: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -20,8 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ... // ...
const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => ( const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div> <div>
@@ -30,7 +30,7 @@ const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize })
keyField="id" keyField="id"
data={ data } data={ data }
columns={ columns } columns={ columns }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
@@ -90,7 +90,7 @@ const Table = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
keyField="id" keyField="id"
data={ data } data={ data }
columns={ columns } columns={ columns }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
noDataIndication={ () => <NoDataIndication /> } noDataIndication={ () => <NoDataIndication /> }
/> />
@@ -116,7 +116,7 @@ class EmptyTableOverlay extends React.Component {
}; };
} }
handleTableChange = ({ page, sizePerPage }) => { handleTableChange = (type, { page, sizePerPage }) => {
const currentIndex = (page - 1) * sizePerPage; const currentIndex = (page - 1) * sizePerPage;
setTimeout(() => { setTimeout(() => {
this.setState(() => ({ this.setState(() => ({

View File

@@ -1,8 +1,8 @@
/* eslint react/no-multi-comp: 0 */ /* eslint react/no-multi-comp: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import overlayFactory from 'react-bootstrap-table2-overlay'; import overlayFactory from 'react-bootstrap-table2-overlay';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -21,8 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import overlayFactory from 'react-bootstrap-table2-overlay'; import overlayFactory from 'react-bootstrap-table2-overlay';
// ... // ...
@@ -34,7 +34,7 @@ const RemotePagination = ({ loading, data, page, sizePerPage, onTableChange, tot
keyField="id" keyField="id"
data={ data } data={ data }
columns={ columns } columns={ columns }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
overlay={ overlayFactory({ spinner: true, background: 'rgba(192,192,192,0.3)' }) } overlay={ overlayFactory({ spinner: true, background: 'rgba(192,192,192,0.3)' }) }
/> />
@@ -99,7 +99,7 @@ const RemotePagination = ({ loading, data, page, sizePerPage, onTableChange, tot
keyField="id" keyField="id"
data={ data } data={ data }
columns={ columns } columns={ columns }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
overlay={ overlayFactory({ spinner: true, background: 'rgba(192,192,192,0.3)' }) } overlay={ overlayFactory({ spinner: true, background: 'rgba(192,192,192,0.3)' }) }
/> />
@@ -127,7 +127,7 @@ class Container extends React.Component {
}; };
} }
handleTableChange = ({ page, sizePerPage }) => { handleTableChange = (type, { page, sizePerPage }) => {
const currentIndex = (page - 1) * sizePerPage; const currentIndex = (page - 1) * sizePerPage;
setTimeout(() => { setTimeout(() => {
this.setState(() => ({ this.setState(() => ({

View File

@@ -1,8 +1,8 @@
/* eslint react/prefer-stateless-function: 0 */ /* eslint react/prefer-stateless-function: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -20,8 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ... // ...
const options = { const options = {
@@ -48,7 +48,7 @@ const options = {
}] // A numeric array is also available. the purpose of above example is custom the text }] // A numeric array is also available. the purpose of above example is custom the text
}; };
<BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginator(options) } /> <BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginationFactory(options) } />
`; `;
const options = { const options = {
paginationSize: 4, paginationSize: 4,
@@ -76,7 +76,7 @@ const options = {
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginator(options) } /> <BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,8 +1,8 @@
/* eslint react/prefer-stateless-function: 0 */ /* eslint react/prefer-stateless-function: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -20,8 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ... // ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
@@ -34,12 +34,12 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
<BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginator() } /> <BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginationFactory() } />
`; `;
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginator() } /> <BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory() } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -2,8 +2,8 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -21,8 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ... // ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
@@ -52,7 +52,7 @@ const options = {
keyField="id" keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
pagination={ paginator(options) } pagination={ paginationFactory(options) }
/> />
`; `;
@@ -75,7 +75,7 @@ export default () => (
keyField="id" keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
pagination={ paginator(options) } pagination={ paginationFactory(options) }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

@@ -2,8 +2,8 @@
/* eslint no-restricted-syntax: 0 */ /* eslint no-restricted-syntax: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -24,8 +24,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
// ... // ...
@@ -50,7 +50,7 @@ const RemoteAll = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
data={ data } data={ data }
columns={ columns } columns={ columns }
filter={ filterFactory() } filter={ filterFactory() }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
@@ -130,7 +130,7 @@ const RemoteAll = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
data={ data } data={ data }
columns={ columns } columns={ columns }
filter={ filterFactory() } filter={ filterFactory() }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>

View File

@@ -0,0 +1,168 @@
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 { 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 cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const RemoteCellEdit = (props) => {
const cellEdit = {
mode: 'click',
errorMessage: props.errorMessage
};
return (
<div>
<BootstrapTable
remote={ { cellEdit: true } }
keyField="id"
data={ props.data }
columns={ columns }
cellEdit={ cellEditFactory(cellEdit) }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
};
RemoteCellEdit.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products,
errorMessage: null
};
}
handleTableChange = (type, { data, cellEdit: { rowId, dataField, newValue } }) => {
setTimeout(() => {
if (newValue === 'test' && dataField === 'name') {
this.setState(() => ({
data,
errorMessage: 'Oops, product name shouldn't be "test"'
}));
} else {
const result = data.map((row) => {
if (row.id === rowId) {
const newRow = { ...row };
newRow[dataField] = newValue;
return newRow;
}
return row;
});
this.setState(() => ({
data: result,
errorMessage: null
}));
}
}, 2000);
}
render() {
return (
<RemoteCellEdit
data={ this.state.data }
errorMessage={ this.state.errorMessage }
onTableChange={ this.handleTableChange }
/>
);
}
}
`;
const RemoteCellEdit = (props) => {
const cellEdit = {
mode: 'click',
errorMessage: props.errorMessage
};
return (
<div>
<BootstrapTable
remote={ { cellEdit: true } }
keyField="id"
data={ props.data }
columns={ columns }
cellEdit={ cellEditFactory(cellEdit) }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
};
RemoteCellEdit.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products,
errorMessage: null
};
}
handleTableChange = (type, { data, cellEdit: { rowId, dataField, newValue } }) => {
setTimeout(() => {
if (newValue === 'test' && dataField === 'name') {
this.setState(() => ({
data,
errorMessage: 'Oops, product name shouldn\'t be "test"'
}));
} else {
const result = data.map((row) => {
if (row.id === rowId) {
const newRow = { ...row };
newRow[dataField] = newValue;
return newRow;
}
return row;
});
this.setState(() => ({
data: result,
errorMessage: null
}));
}
}, 2000);
}
render() {
return (
<RemoteCellEdit
data={ this.state.data }
errorMessage={ this.state.errorMessage }
onTableChange={ this.handleTableChange }
/>
);
}
}
export default Container;

View File

@@ -2,7 +2,7 @@
/* eslint no-restricted-syntax: 0 */ /* eslint no-restricted-syntax: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,8 +1,8 @@
/* eslint react/no-multi-comp: 0 */ /* eslint react/no-multi-comp: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -20,8 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import paginator from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ... // ...
const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => ( const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div> <div>
@@ -30,7 +30,7 @@ const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize })
keyField="id" keyField="id"
data={ data } data={ data }
columns={ columns } columns={ columns }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
@@ -80,7 +80,7 @@ const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize })
keyField="id" keyField="id"
data={ data } data={ data }
columns={ columns } columns={ columns }
pagination={ paginator({ page, sizePerPage, totalSize }) } pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange } onTableChange={ onTableChange }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>

View File

@@ -0,0 +1,106 @@
/* eslint no-restricted-syntax: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(5);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
sort: true
}, {
dataField: 'price',
text: 'Product Price',
sort: true
}];
const sourceCode = `\
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
const RemoteSort = props => (
<div>
<BootstrapTable
remote={ { sort: true } }
keyField="id"
data={ props.data }
columns={ columns }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
RemoteSort.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products
};
}
handleTableChange = (type, { sortField, sortOrder, data }) => {
setTimeout(() => {
let result;
if (sortOrder === 'asc') {
result = data.sort((a, b) => {
if (a[sortField] > b[sortField]) {
return 1;
} else if (b[sortField] > a[sortField]) {
return -1;
}
return 0;
});
} else {
result = data.sort((a, b) => {
if (a[sortField] > b[sortField]) {
return -1;
} else if (b[sortField] > a[sortField]) {
return 1;
}
return 0;
});
}
this.setState(() => ({
data: result
}));
}, 2000);
}
render() {
return (
<RemoteSort
data={ this.state.data }
onTableChange={ this.handleTableChange }
/>
);
}
}
export default Container;

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -2,7 +2,7 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -2,7 +2,7 @@
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint react/prefer-stateless-function: 0 */ /* eslint react/prefer-stateless-function: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -5,7 +5,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,7 +1,7 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table2'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';

View File

@@ -1,12 +1,14 @@
{ {
"name": "react-bootstrap-table2-example", "name": "react-bootstrap-table2-example",
"version": "0.0.1", "version": "0.0.3",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true,
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"storybook": "start-storybook -p 6006", "storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook" "gh-pages:clean": "rimraf ./storybook-static",
"gh-pages:build": "build-storybook"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@@ -16,15 +18,12 @@
"react-dom": "^15.0.0" "react-dom": "^15.0.0"
}, },
"dependencies": { "dependencies": {
"bootstrap": "^3.3.7", "bootstrap": "^3.3.7"
"react-bootstrap-table2": "0.0.1",
"react-bootstrap-table2-paginator": "0.0.1",
"react-bootstrap-table2-overlay": "0.0.1",
"react-bootstrap-table2-filter": "0.0.1"
}, },
"devDependencies": { "devDependencies": {
"@storybook/addon-console": "^1.0.0", "@storybook/addon-console": "^1.0.0",
"@storybook/react": "^3.2.8", "@storybook/react": "^3.2.8",
"babel-preset-env": "^1.6.1",
"react-redux": "^5.0.6", "react-redux": "^5.0.6",
"redux": "^3.7.2", "redux": "^3.7.2",
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",

View File

@@ -1,18 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>react-bootstrap-table demo</title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.js"></script>
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<script src="https://use.fontawesome.com/f52b8fd2c4.js"></script> -->
</head>
<body>
<div id="example"></div>
</body>
</html>

View File

@@ -1,118 +0,0 @@
/* eslint no-unused-vars: 0 */
/* eslint no-debugger: 0 */
/* eslint arrow-body-style: 0 */
import React from 'react';
import ReactDom from 'react-dom';
import BootstrapTable from 'react-bootstrap-table2';
require('react-bootstrap-table2/style/react-bootstrap-table.scss');
const products = [];
function addProducts(quantity) {
const startId = products.length;
for (let i = 0; i < quantity; i += 1) {
const id = startId + i;
products.push({
id,
name: `Item name ${id}`,
price: 2100 + i,
nest: {
address: 'Address 1',
postcal: '0922-1234'
}
});
}
}
addProducts(5);
const columns = [{
dataField: 'id',
text: 'Product ID',
style: {
backgroundColor: 'red'
},
classes: 'my-xxx'
}, {
dataField: 'name',
text: 'Product Name',
headerTitle: true,
formatter: (cell, row) =>
(<h3>{ cell }::: ${ row.price }</h3>),
validator: (newValue, row, column) => {
const validationForm = {
valid: true,
message: null
};
validationForm.valid = false;
validationForm.message = 'Invalid message';
return validationForm;
}
}, {
dataField: 'price',
text: 'Product Price',
validator: (newValue, row, column) => {
if (newValue < 2000) {
return {
valid: false,
message: 'Price should bigger than 2000'
};
}
return true;
}
}, {
dataField: 'nest.address',
text: 'Address'
}, {
dataField: 'nest.postcal',
text: 'Postal',
editable: true,
validator: (newValue, row, column) => true
}];
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const cellEdit = {
mode: 'click',
blurToSave: true,
// beforeSaveCell: (oldValue, newValue, row, column) => {
// console.log('beforeSavecell');
// // console.log(oldValue);
// // console.log(newValue);
// // console.log(row);
// // console.log(column);
// },
// afterSaveCell: (oldValue, newValue, row, column) => {
// console.log('aftersavecell');
// // console.log(oldValue);
// // console.log(newValue);
// // console.log(row);
// // console.log(column);
// }
onUpdate: (rowId, dataField, newValue) => {
return sleep(1000).then(() => {
// return { forceUpdate: true };
throw new Error('test is not successfully');
});
}
// nonEditableRows: () => [1, 3, 7]
};
// let Table = withCellEdit({
// mode: 'click',
// blurToSave: true,
// onEditing: (rowId, dataField, newValue) => {
// return sleep(1000).then(() => {
// // return { forceUpdate: true };
// throw new Error('test is not successfully');
// });
// }
// })(BootstrapTable);
// Table = createTable(Table);
ReactDom.render(
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />,
document.getElementById('example'));

View File

@@ -63,8 +63,6 @@ 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 CellEditWithPromise from 'examples/cell-edit/cell-edit-with-promise-table';
import CellEditWithRedux from 'examples/cell-edit/cell-edit-with-redux-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';
@@ -88,16 +86,18 @@ import EmptyTableOverlay from 'examples/loading-overlay/empty-table-overlay';
import TableOverlay from 'examples/loading-overlay/table-overlay'; import TableOverlay from 'examples/loading-overlay/table-overlay';
// remote // remote
import RemoteSort from 'examples/remote/remote-sort';
import RemoteFilter from 'examples/remote/remote-filter'; import RemoteFilter from 'examples/remote/remote-filter';
import RemotePaginationTable from 'examples/remote/remote-pagination'; import RemotePaginationTable from 'examples/remote/remote-pagination';
import RemoteCellEdit from 'examples/remote/remote-celledit';
import RemoteAll from 'examples/remote/remote-all'; import RemoteAll from 'examples/remote/remote-all';
// css style // css style
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import 'stories/stylesheet/tomorrow.min.css'; import 'stories/stylesheet/tomorrow.min.css';
import 'stories/stylesheet/storybook.scss'; import 'stories/stylesheet/storybook.scss';
import 'react-bootstrap-table2/style/react-bootstrap-table.scss'; import 'react-bootstrap-table2/style/react-bootstrap-table2.scss';
import 'react-bootstrap-table2-paginator/style/react-bootstrap-table-paginator.scss'; import 'react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss';
// import { action } from '@storybook/addon-actions'; // import { action } from '@storybook/addon-actions';
@@ -164,9 +164,7 @@ storiesOf('Cell Editing', module)
.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 When Editing', () => <CellEditStyleTable />)
.add('Custom Cell Classes When Editing', () => <CellEditClassTable />) .add('Custom Cell Classes When Editing', () => <CellEditClassTable />);
.add('Async Cell Editing(Promise)', () => <CellEditWithPromise />)
.add('Async Cell Editing(Redux)', () => <CellEditWithRedux />);
storiesOf('Row Selection', module) storiesOf('Row Selection', module)
.add('Single Selection', () => <SingleSelectionTable />) .add('Single Selection', () => <SingleSelectionTable />)
@@ -190,6 +188,8 @@ storiesOf('EmptyTableOverlay', module)
.add('Table Overlay', () => <TableOverlay />); .add('Table Overlay', () => <TableOverlay />);
storiesOf('Remote', module) storiesOf('Remote', module)
.add('Remote Sort', () => <RemoteSort />)
.add('Remote Filter', () => <RemoteFilter />) .add('Remote Filter', () => <RemoteFilter />)
.add('Remote Pagination', () => <RemotePaginationTable />) .add('Remote Pagination', () => <RemotePaginationTable />)
.add('Remote Cell Editing', () => <RemoteCellEdit />)
.add('Remote All', () => <RemoteAll />); .add('Remote All', () => <RemoteAll />);

View File

@@ -1,13 +1,24 @@
# react-bootstrap-table2-filter # react-bootstrap-table2-filter
## Filters `react-bootstrap-table2` separate the filter core code base to [`react-bootstrap-table2-filter`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-filter), so there's a little bit different when you use column filter than `react-bootstrap-table`. In the following, we are going to show you how to enable the column filter:
* Text (`textFilter`) **[Live Demo For Column Filter](https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/gh-pages-src/storybook/index.html?selectedKind=Column%20Filter)**
You can get all of above filters via import and these filters are a factory function to create a individual filter instance. -----
In addition, for some simple customization reasons, these factory function allow to pass some props.
### Text Filter ## Install
```sh
$ 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:
* TextFilter
* **Coming soon!**
## Text Filter
Following is a quick demo for enable the column filter on **Product Price** column!!
```js ```js
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
@@ -23,18 +34,20 @@ const columns = [
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } /> <BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
``` ```
Following we list all the availabe props for `textFilter` function: In addition, we preserve all of the filter features and functionality in legacy `react-bootstrap-table`, but in different way to do it:
```js ```js
import { Comparator } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
// omit... // omit...
const customTextFilter = textFilter({ const priceFilter = textFilter({
placeholder: 'My Custom PlaceHolder', // custom the input placeholder placeholder: 'My Custom PlaceHolder', // custom the input placeholder
style: { ... }, // your custom styles on input
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
delay: 1000, // how long will trigger filtering after user typing, default is 500 ms comparator: Comparator.EQ, // default is Comparator.LIKE
comparator: Comparator.EQ // default is Comparator.LIKE style: { ... }, // your custom styles on input
delay: 1000 // how long will trigger filtering after user typing, default is 500 ms
}); });
// omit...
``` ```

View File

@@ -1,9 +1,9 @@
import TextFilter from './components/text'; import TextFilter from './src/components/text';
import FilterWrapper from './wrapper'; import wrapperFactory from './src/wrapper';
import * as Comparison from './comparison'; import * as Comparison from './src/comparison';
export default (options = {}) => ({ export default (options = {}) => ({
FilterWrapper, wrapperFactory,
options options
}); });

View File

@@ -1,11 +1,39 @@
{ {
"name": "react-bootstrap-table2-filter", "name": "react-bootstrap-table2-filter",
"version": "0.0.1", "version": "0.0.3",
"description": "it's the column filter addon for react-bootstrap-table2", "description": "it's a column filter addon for react-bootstrap-table2",
"main": "src/index.js", "main": "./lib/index.js",
"scripts": { "repository": {
"test": "echo \"Error: no test specified\" && exit 1" "type": "git",
"url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git"
}, },
"author": "", "license": "MIT",
"license": "ISC" "keywords": [
"react",
"bootstrap",
"table",
"grid",
"react-bootstrap-table-addons",
"react-component"
],
"files": [
"lib/",
"dist/"
],
"tags": [
"react"
],
"author": "AllenFang",
"contributors": [
{
"name": "Chun-MingChen",
"email": "nick830314@gmail.com",
"url": "https://github.com/Chun-MingChen"
}
],
"peerDependencies": {
"prop-types": "^15.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0"
}
} }

View File

@@ -1,76 +1,74 @@
/* eslint react/prop-types: 0 */ /* eslint no-param-reassign: 0 */
import { 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 } from './comparison';
export default class FilterWrapper extends Component { export default (Base, {
static propTypes = { _,
store: PropTypes.object.isRequired, remoteResolver
columns: PropTypes.array.isRequired, }) =>
baseElement: PropTypes.func.isRequired, class FilterWrapper extends remoteResolver(Component) {
onRemoteFilterChange: PropTypes.func.isRequired, static propTypes = {
// refactoring later store: PropTypes.object.isRequired,
_: PropTypes.object.isRequired columns: PropTypes.array.isRequired
}
constructor(props) {
super(props);
this.state = { currFilters: {}, isDataChanged: false };
this.onFilter = this.onFilter.bind(this);
}
componentWillReceiveProps(nextProps) {
// consider to use lodash.isEqual
if (JSON.stringify(this.state.currFilters) !== JSON.stringify(nextProps.store.filters)) {
this.setState(() => ({ isDataChanged: true, currFilters: nextProps.store.filters }));
} else {
this.setState(() => ({ isDataChanged: false }));
}
}
onFilter(column, filterVal, filterType) {
const { store, columns, _, onRemoteFilterChange } = this.props;
const currFilters = Object.assign({}, this.state.currFilters);
const { dataField, filter } = column;
if (!_.isDefined(filterVal) || filterVal === '') {
delete currFilters[dataField];
} else {
const { comparator = LIKE } = filter.props;
currFilters[dataField] = { filterVal, filterType, comparator };
}
store.filters = currFilters;
if (this.isRemote() || this.isPaginationRemote()) {
onRemoteFilterChange(this.isPaginationRemote());
// 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); constructor(props) {
this.setState(() => ({ currFilters, isDataChanged: true })); super(props);
} this.state = { currFilters: {}, isDataChanged: props.isDataChanged || false };
this.onFilter = this.onFilter.bind(this);
}
// refactoring later componentWillReceiveProps({ isDataChanged, store, columns }) {
isRemote() { // consider to use lodash.isEqual
const { remote } = this.props; if (JSON.stringify(this.state.currFilters) !== JSON.stringify(store.filters)) {
return remote === true || (typeof remote === 'object' && remote.filter); this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
} } else if (isDataChanged) {
if (!(this.isRemoteFiltering() || this.isRemotePagination()) &&
Object.keys(this.state.currFilters).length > 0) {
store.filteredData = filters(store, columns, _)(this.state.currFilters);
}
this.setState(() => ({ isDataChanged }));
} else {
this.setState(() => ({ isDataChanged: false }));
}
}
// refactoring later onFilter(column, filterVal, filterType) {
isPaginationRemote() { const { store, columns } = this.props;
const { remote } = this.props; const currFilters = Object.assign({}, this.state.currFilters);
return remote === true || (typeof remote === 'object' && remote.pagination); const { dataField, filter } = column;
}
render() { if (!_.isDefined(filterVal) || filterVal === '') {
return this.props.baseElement({ delete currFilters[dataField];
...this.props, } else {
key: 'table', const { comparator = LIKE } = filter.props;
onFilter: this.onFilter, currFilters[dataField] = { filterVal, filterType, comparator };
isDataChanged: this.state.isDataChanged }
}); store.filters = currFilters;
}
} if (this.isRemoteFiltering() || this.isRemotePagination()) {
this.handleRemoteFilterChange();
// when remote filtering is enable, dont set currFilters state
// in the componentWillReceiveProps,
// it's the key point that we can know the filter is changed
return;
}
store.filteredData = filters(store, columns, _)(currFilters);
this.setState(() => ({ currFilters, isDataChanged: true }));
}
render() {
return (
<Base
{ ...this.props }
data={ this.props.store.data }
onFilter={ this.onFilter }
isDataChanged={ this.state.isDataChanged }
/>
);
}
};

Some files were not shown because too many files have changed in this diff Show More