mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
Merge pull request #635 from react-bootstrap-table/develop
20181028 release
This commit is contained in:
commit
27c3cdab29
@ -62,6 +62,24 @@ const cellEdit = {
|
||||
}
|
||||
```
|
||||
|
||||
If you want to perform a async `beforeSaveCell`, you can do it like that:
|
||||
|
||||
```js
|
||||
const cellEdit: {
|
||||
// omit...
|
||||
beforeSaveCell(oldValue, newValue, row, column, done) {
|
||||
setTimeout(() => {
|
||||
if (confirm('Do you want to accep this change?')) {
|
||||
done(); // contine to save the changes
|
||||
} else {
|
||||
done(false); // reject the changes
|
||||
}
|
||||
}, 0);
|
||||
return { async: true };
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### <a name='afterSaveCell'>cellEdit.afterSaveCell - [Function]</a>
|
||||
This callback function will be called after updating cell.
|
||||
|
||||
|
||||
@ -379,17 +379,27 @@ A new `String` will be the result of element headerAlign.
|
||||
|
||||
|
||||
## <a name='events'>column.events - [Object]</a>
|
||||
You can assign any [HTML Event](https://www.w3schools.com/tags/ref_eventattributes.asp) on table column via event property:
|
||||
You can assign any [HTML Event](https://www.w3schools.com/tags/ref_eventattributes.asp) on table column via `events` property.
|
||||
|
||||
`react-bootstrap-table2` currently only support following events which will receive some specific information:
|
||||
|
||||
* onClick
|
||||
* onDoubleClick
|
||||
* onMouseEnter
|
||||
* onMouseLeave
|
||||
* onContextMenu
|
||||
|
||||
```js
|
||||
{
|
||||
// omit...
|
||||
events: {
|
||||
onClick: e => { ... }
|
||||
onClick: (e, column, columnIndex, row, rowIndex) => { ... },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the events is not listed above, the callback function will only pass the `event` object.
|
||||
|
||||
## <a name='headerEvents'>column.headerEvents - [Object]</a>
|
||||
`headerEvents` same as [`column.events`](#events) but this is for header column.
|
||||
|
||||
@ -543,6 +553,28 @@ The return value can be a bool or an object. If your validation is pass, return
|
||||
}
|
||||
```
|
||||
|
||||
If you want to perform a asycn validation, you can do it like this:
|
||||
```js
|
||||
{
|
||||
// omit...
|
||||
validator: (newValue, row, column, done) => {
|
||||
settimeout(() => {
|
||||
// async validation ok
|
||||
return done();
|
||||
|
||||
// async validation not ok
|
||||
return done({
|
||||
valid: false,
|
||||
message: 'SOME_REASON_HERE'
|
||||
});
|
||||
|
||||
}, 2000);
|
||||
return { async: true };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## <a name='editCellStyle'>column.editCellStyle - [Object | Function]</a>
|
||||
You can use `column.editCellStyle` to custom the style of `<td>` when cell editing. It like most of customizable functionality, it also accept a callback function with following params:
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
### Setup
|
||||
```bash
|
||||
$ git clone https://github.com/react-bootstrap-table/react-bootstrap-table2.git
|
||||
$ cd react-bootstrap-table
|
||||
$ cd react-bootstrap-table2
|
||||
$ npm install
|
||||
$ lerna bootstrap # ./node_modules/.bin/lerna bootstrap
|
||||
```
|
||||
@ -25,4 +25,4 @@ $ npm run storybook
|
||||
$ npm test
|
||||
$ npm run test:watch # for watch mode
|
||||
$ npm run test:coverage # generate coverage report
|
||||
```
|
||||
```
|
||||
|
||||
@ -31,6 +31,7 @@ export default (
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.doUpdate = this.doUpdate.bind(this);
|
||||
this.startEditing = this.startEditing.bind(this);
|
||||
this.escapeEditing = this.escapeEditing.bind(this);
|
||||
this.completeEditing = this.completeEditing.bind(this);
|
||||
@ -55,11 +56,36 @@ export default (
|
||||
}
|
||||
|
||||
handleCellUpdate(row, column, newValue) {
|
||||
const { keyField, cellEdit, data } = this.props;
|
||||
const { beforeSaveCell, afterSaveCell } = cellEdit.options;
|
||||
const { cellEdit } = this.props;
|
||||
const { beforeSaveCell } = cellEdit.options;
|
||||
const oldValue = _.get(row, column.dataField);
|
||||
const beforeSaveCellDone = (result = true) => {
|
||||
if (result) {
|
||||
this.doUpdate(row, column, newValue);
|
||||
} else {
|
||||
this.escapeEditing();
|
||||
}
|
||||
};
|
||||
if (_.isFunction(beforeSaveCell)) {
|
||||
const result = beforeSaveCell(
|
||||
oldValue,
|
||||
newValue,
|
||||
row,
|
||||
column,
|
||||
beforeSaveCellDone
|
||||
);
|
||||
if (_.isObject(result) && result.async) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.doUpdate(row, column, newValue);
|
||||
}
|
||||
|
||||
doUpdate(row, column, newValue) {
|
||||
const { keyField, cellEdit, data } = this.props;
|
||||
const { afterSaveCell } = cellEdit.options;
|
||||
const rowId = _.get(row, keyField);
|
||||
if (_.isFunction(beforeSaveCell)) beforeSaveCell(oldValue, newValue, row, column);
|
||||
const oldValue = _.get(row, column.dataField);
|
||||
if (isRemoteCellEdit()) {
|
||||
handleCellChange(rowId, column.dataField, newValue);
|
||||
} else {
|
||||
|
||||
@ -44,6 +44,8 @@ export default (_, onStartEdit) =>
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.beforeComplete = this.beforeComplete.bind(this);
|
||||
this.asyncbeforeCompete = this.asyncbeforeCompete.bind(this);
|
||||
this.displayErrorMessage = this.displayErrorMessage.bind(this);
|
||||
this.state = {
|
||||
invalidMessage: null
|
||||
};
|
||||
@ -79,16 +81,41 @@ export default (_, onStartEdit) =>
|
||||
}, timeToCloseMessage);
|
||||
}
|
||||
|
||||
displayErrorMessage(message) {
|
||||
this.setState(() => ({
|
||||
invalidMessage: message
|
||||
}));
|
||||
this.createTimer();
|
||||
}
|
||||
|
||||
asyncbeforeCompete(newValue) {
|
||||
return (result = { valid: true }) => {
|
||||
const { valid, message } = result;
|
||||
const { onUpdate, row, column } = this.props;
|
||||
if (!valid) {
|
||||
this.displayErrorMessage(message);
|
||||
return;
|
||||
}
|
||||
onUpdate(row, column, newValue);
|
||||
};
|
||||
}
|
||||
|
||||
beforeComplete(newValue) {
|
||||
const { onUpdate, row, column } = 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;
|
||||
const validateForm = column.validator(
|
||||
newValue,
|
||||
row,
|
||||
column,
|
||||
this.asyncbeforeCompete(newValue)
|
||||
);
|
||||
if (_.isObject(validateForm)) {
|
||||
if (validateForm.async) {
|
||||
return;
|
||||
} else if (!validateForm.valid) {
|
||||
this.displayErrorMessage(validateForm.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
onUpdate(row, column, newValue);
|
||||
|
||||
@ -235,7 +235,8 @@ describe('CellEditContext', () => {
|
||||
|
||||
it('should call cellEdit.beforeSaveCell correctly', () => {
|
||||
expect(beforeSaveCell).toHaveBeenCalledTimes(1);
|
||||
expect(beforeSaveCell).toHaveBeenCalledWith(oldValue, newValue, row, column);
|
||||
expect(beforeSaveCell)
|
||||
.toHaveBeenCalledWith(oldValue, newValue, row, column, expect.anything());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
86
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-async-hooks-table.js
vendored
Normal file
86
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-async-hooks-table.js
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
/* eslint no-console: 0 */
|
||||
/* eslint no-alert: 0 */
|
||||
import React from 'react';
|
||||
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator } from 'utils/common';
|
||||
|
||||
const products = productsGenerator();
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
function beforeSaveCell(oldValue, newValue, row, column, done) {
|
||||
setTimeout(() => {
|
||||
if (confirm('Do you want to accep this change?')) {
|
||||
done(true);
|
||||
} else {
|
||||
done(false);
|
||||
}
|
||||
}, 0);
|
||||
return { async: true };
|
||||
}
|
||||
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({
|
||||
mode: 'click',
|
||||
beforeSaveCell
|
||||
}) }
|
||||
/>
|
||||
`;
|
||||
|
||||
function beforeSaveCell(oldValue, newValue, row, column, done) {
|
||||
setTimeout(() => {
|
||||
if (confirm('Do you want to accep this change?')) {
|
||||
done(true);
|
||||
} else {
|
||||
done(false);
|
||||
}
|
||||
}, 0);
|
||||
return { async: true };
|
||||
}
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h2>You will get a confirm prompt when you try to save a cell</h2>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({
|
||||
mode: 'click',
|
||||
beforeSaveCell
|
||||
}) }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
101
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-async-validator-table.js
vendored
Normal file
101
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-async-validator-table.js
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
import React from 'react';
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator } from 'utils/common';
|
||||
|
||||
const products = productsGenerator();
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
validator: (newValue, row, column, done) => {
|
||||
setTimeout(() => {
|
||||
if (isNaN(newValue)) {
|
||||
return done({
|
||||
valid: false,
|
||||
message: 'Price should be numeric'
|
||||
});
|
||||
}
|
||||
if (newValue < 2000) {
|
||||
return done({
|
||||
valid: false,
|
||||
message: 'Price should bigger than 2000'
|
||||
});
|
||||
}
|
||||
return done();
|
||||
}, 2000);
|
||||
return {
|
||||
async: true
|
||||
};
|
||||
}
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
validator: (newValue, row, column, done) => {
|
||||
setTimeout(() => {
|
||||
if (isNaN(newValue)) {
|
||||
return done({
|
||||
valid: false,
|
||||
message: 'Price should be numeric'
|
||||
});
|
||||
}
|
||||
if (newValue < 2000) {
|
||||
return done({
|
||||
valid: false,
|
||||
message: 'Price should bigger than 2000'
|
||||
});
|
||||
}
|
||||
return done();
|
||||
}, 2000);
|
||||
return {
|
||||
async: true
|
||||
};
|
||||
}
|
||||
}];
|
||||
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({
|
||||
mode: 'click',
|
||||
blurToSave: true
|
||||
}) }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h3>Product Price should bigger than $2000</h3>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({
|
||||
mode: 'click',
|
||||
blurToSave: true
|
||||
}) }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@ -1,5 +1,6 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
/* eslint no-alert: 0 */
|
||||
/* eslint no-console: 0 */
|
||||
import React from 'react';
|
||||
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
@ -12,7 +13,22 @@ const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
events: {
|
||||
onClick: () => alert('Click on Product ID field')
|
||||
onClick: (e, column, columnIndex, row, rowIndex) => {
|
||||
console.log(e);
|
||||
console.log(column);
|
||||
console.log(columnIndex);
|
||||
console.log(row);
|
||||
console.log(rowIndex);
|
||||
alert('Click on Product ID field');
|
||||
},
|
||||
onMouseEnter: (e, column, columnIndex, row, rowIndex) => {
|
||||
console.log(e);
|
||||
console.log(column);
|
||||
console.log(columnIndex);
|
||||
console.log(row);
|
||||
console.log(rowIndex);
|
||||
console.log('onMouseEnter on Product ID field');
|
||||
}
|
||||
}
|
||||
}, {
|
||||
dataField: 'name',
|
||||
@ -29,7 +45,22 @@ const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
events: {
|
||||
onClick: () => alert('Click on Product ID field')
|
||||
onClick: (e, column, columnIndex, row, rowIndex) => {
|
||||
console.log(e);
|
||||
console.log(column);
|
||||
console.log(columnIndex);
|
||||
console.log(row);
|
||||
console.log(rowIndex);
|
||||
alert('Click on Product ID field');
|
||||
},
|
||||
onMouseEnter: (e, column, columnIndex, row, rowIndex) => {
|
||||
console.log(e);
|
||||
console.log(column);
|
||||
console.log(columnIndex);
|
||||
console.log(row);
|
||||
console.log(rowIndex);
|
||||
console.log('onMouseEnter on Product ID field');
|
||||
}
|
||||
}
|
||||
}, {
|
||||
dataField: 'name',
|
||||
@ -44,7 +75,7 @@ const columns = [{
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h3>Try to Click on Product ID columns</h3>
|
||||
<h3>Try to Click or Mouse over on Product ID columns</h3>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
|
||||
@ -97,7 +97,9 @@ import RowLevelEditableTable from 'examples/cell-edit/row-level-editable-table';
|
||||
import ColumnLevelEditableTable from 'examples/cell-edit/column-level-editable-table';
|
||||
import CellLevelEditable from 'examples/cell-edit/cell-level-editable-table';
|
||||
import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
|
||||
import AsyncCellEditHooks from 'examples/cell-edit/cell-edit-async-hooks-table';
|
||||
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
|
||||
import AsyncCellEditValidator from 'examples/cell-edit/cell-edit-async-validator-table';
|
||||
import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table';
|
||||
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
|
||||
import AutoSelectTextInput from 'examples/cell-edit/auto-select-text-input-table';
|
||||
@ -288,7 +290,9 @@ storiesOf('Cell Editing', module)
|
||||
.add('Column Level Editable', () => <ColumnLevelEditableTable />)
|
||||
.add('Cell Level Editable', () => <CellLevelEditable />)
|
||||
.add('Rich Hook Functions', () => <CellEditHooks />)
|
||||
.add('Async Hook Functions', () => <AsyncCellEditHooks />)
|
||||
.add('Validation', () => <CellEditValidator />)
|
||||
.add('Async Validation', () => <AsyncCellEditValidator />)
|
||||
.add('Auto Select Text Input', () => <AutoSelectTextInput />)
|
||||
.add('Custom Cell Style', () => <CellEditStyleTable />)
|
||||
.add('Custom Cell Classes', () => <CellEditClassTable />)
|
||||
|
||||
@ -15,13 +15,12 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
||||
super(props);
|
||||
this.validateProps();
|
||||
if (props.registerExposedAPI) {
|
||||
const getData = () => this.getData();
|
||||
props.registerExposedAPI(getData);
|
||||
props.registerExposedAPI(this.getData);
|
||||
}
|
||||
}
|
||||
|
||||
// Exposed APIs
|
||||
getData = () => {
|
||||
getData() {
|
||||
return this.props.data;
|
||||
}
|
||||
|
||||
|
||||
@ -7,17 +7,16 @@ const events = [
|
||||
];
|
||||
|
||||
export default ExtendBase =>
|
||||
class RowEventDelegater extends ExtendBase {
|
||||
class CellEventDelegater extends ExtendBase {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.clickNum = 0;
|
||||
this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this);
|
||||
}
|
||||
|
||||
createDefaultEventHandler(cb) {
|
||||
return (e) => {
|
||||
const { row, rowIndex } = this.props;
|
||||
cb(e, row, rowIndex);
|
||||
const { column, columnIndex } = this.props;
|
||||
cb(e, column, columnIndex);
|
||||
};
|
||||
}
|
||||
|
||||
5
packages/react-bootstrap-table2/src/cell.js
vendored
5
packages/react-bootstrap-table2/src/cell.js
vendored
@ -2,9 +2,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import eventDelegater from './cell-event-delegater';
|
||||
import _ from './utils';
|
||||
|
||||
class Cell extends Component {
|
||||
class Cell extends eventDelegater(Component) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleEditingCell = this.handleEditingCell.bind(this);
|
||||
@ -73,7 +74,7 @@ class Cell extends Component {
|
||||
formatter,
|
||||
formatExtraData
|
||||
} = column;
|
||||
const attrs = { ...rest };
|
||||
const attrs = this.delegate({ ...rest });
|
||||
let content = column.isDummyField ? null : _.get(row, dataField);
|
||||
|
||||
if (formatter) {
|
||||
|
||||
@ -50,13 +50,21 @@ export default class RowPureContent extends React.Component {
|
||||
// render cell
|
||||
let cellTitle;
|
||||
let cellStyle = {};
|
||||
const cellAttrs = {
|
||||
let cellAttrs = {
|
||||
..._.isFunction(column.attrs)
|
||||
? column.attrs(content, row, rowIndex, index)
|
||||
: column.attrs,
|
||||
...column.events
|
||||
: column.attrs
|
||||
};
|
||||
|
||||
if (column.events) {
|
||||
const events = Object.assign({}, column.events);
|
||||
Object.keys(Object.assign({}, column.events)).forEach((key) => {
|
||||
const originFn = events[key];
|
||||
events[key] = (...rest) => originFn(...rest, row, rowIndex);
|
||||
});
|
||||
cellAttrs = { ...cellAttrs, ...events };
|
||||
}
|
||||
|
||||
const cellClasses = _.isFunction(column.classes)
|
||||
? column.classes(content, row, rowIndex, index)
|
||||
: column.classes;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user