mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
fix #101
* implement cell editor style/class * add stories for custom cell editor style and class * patch testing for cell editor style and class * patch docs for cell editor style and class
This commit is contained in:
parent
afef2adcaf
commit
cb6410bbe4
@ -27,6 +27,8 @@ Available properties in a column object:
|
||||
* [headerAttrs](#headerAttrs)
|
||||
* [editable](#editable)
|
||||
* [validator](#validator)
|
||||
* [editCellStyle](#editCellStyle)
|
||||
* [editCellClasses](#editCellClasses)
|
||||
|
||||
Following is a most simplest and basic usage:
|
||||
|
||||
@ -450,4 +452,46 @@ The return value can be a bool or an object. If your valiation is pass, return `
|
||||
valid: false,
|
||||
message: 'SOME_REASON_HERE'
|
||||
}
|
||||
```
|
||||
|
||||
## <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:
|
||||
|
||||
**Parameters**
|
||||
* `cell`: The value of current cell.
|
||||
* `row`: The object of `row` being processed in the `BootstrapTable`.
|
||||
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
|
||||
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
|
||||
|
||||
```js
|
||||
{
|
||||
editCellStyle: { ... }
|
||||
}
|
||||
```
|
||||
Or take a callback function
|
||||
|
||||
```js
|
||||
{
|
||||
editCellStyle: (cell, row, rowIndex, colIndex) => {
|
||||
// it is suppose to return an object
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## <a name='editCellClasses'>column.editCellClasses - [Object | Function]</a>
|
||||
You can use `column.editCellClasses` to add custom class on `<td>` when cell editing. It's same as [`column.editCellStyle`](#editCellStyle) which also accept a callback function to able to custom your class more flexible. Following is the arguments of this callback function: `cell`, `row`, `rowIndex`, `colIndex`.
|
||||
|
||||
```js
|
||||
{
|
||||
editCellClasses: 'custom-class'
|
||||
}
|
||||
```
|
||||
Or take a callback function
|
||||
|
||||
```js
|
||||
{
|
||||
editCellClasses: (cell, row, rowIndex, colIndex) => {
|
||||
// it is suppose to return a string
|
||||
}
|
||||
}
|
||||
```
|
||||
59
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-class-table.js
vendored
Normal file
59
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-class-table.js
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
import React from 'react';
|
||||
|
||||
import BootstrapTable from 'react-bootstrap-table2';
|
||||
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',
|
||||
editCellClasses: 'editing-name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
editCellClasses: (cell, row, rowIndex, colIndex) =>
|
||||
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
editCellClasses: 'editing-name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
editCellClasses: (cell, row, rowIndex, colIndex) =>
|
||||
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
|
||||
}];
|
||||
|
||||
const cellEdit = {
|
||||
mode: 'click'
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
`;
|
||||
|
||||
const cellEdit = {
|
||||
mode: 'click'
|
||||
};
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
67
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-style-table.js
vendored
Normal file
67
packages/react-bootstrap-table2-example/examples/cell-edit/cell-edit-style-table.js
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
import React from 'react';
|
||||
|
||||
import BootstrapTable from 'react-bootstrap-table2';
|
||||
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',
|
||||
editCellStyle: {
|
||||
backgroundColor: '#20B2AA'
|
||||
}
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
editCellStyle: (cell, row, rowIndex, colIndex) => {
|
||||
const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF';
|
||||
return { backgroundColor };
|
||||
}
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
editCellStyle: {
|
||||
backgroundColor: '#20B2AA'
|
||||
}
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
editCellStyle: (cell, row, rowIndex, colIndex) => {
|
||||
const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF';
|
||||
return { backgroundColor };
|
||||
}
|
||||
}];
|
||||
|
||||
const cellEdit = {
|
||||
mode: 'click'
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
`;
|
||||
|
||||
const cellEdit = {
|
||||
mode: 'click'
|
||||
};
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@ -45,6 +45,8 @@ import ColumnLevelEditableTable from 'examples/cell-edit/column-level-editable-t
|
||||
import CellLevelEditable from 'examples/cell-edit/cell-level-editable-table';
|
||||
import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
|
||||
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
|
||||
import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-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';
|
||||
|
||||
@ -105,6 +107,8 @@ storiesOf('Cell Editing', module)
|
||||
.add('Cell Level Editable', () => <CellLevelEditable />)
|
||||
.add('Rich Hook Functions', () => <CellEditHooks />)
|
||||
.add('Validation', () => <CellEditValidator />)
|
||||
.add('Custom Cell Style When Editing', () => <CellEditStyleTable />)
|
||||
.add('Custom Cell Classes When Editing', () => <CellEditClassTable />)
|
||||
.add('Async Cell Editing(Promise)', () => <CellEditWithPromise />)
|
||||
.add('Async Cell Editing(Redux)', () => <CellEditWithRedux />);
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
.editing-name {
|
||||
background-color: #20B2AA;
|
||||
}
|
||||
|
||||
.editing-price-bigger-than-2101 {
|
||||
background-color: #00BFFF;
|
||||
}
|
||||
|
||||
.editing-price-small-than-2101 {
|
||||
background-color: #00FFFF;
|
||||
}
|
||||
@ -5,3 +5,4 @@
|
||||
|
||||
@import "welcome/index";
|
||||
@import "columns/index";
|
||||
@import "cell-edit/index";
|
||||
@ -96,7 +96,7 @@ class EditingCell extends Component {
|
||||
|
||||
render() {
|
||||
const { invalidMessage } = this.state;
|
||||
const { row, column } = this.props;
|
||||
const { row, column, className, style } = this.props;
|
||||
const { dataField } = column;
|
||||
|
||||
const value = _.get(row, dataField);
|
||||
@ -108,7 +108,10 @@ class EditingCell extends Component {
|
||||
const hasError = _.isDefined(invalidMessage);
|
||||
const editorClass = hasError ? cs('animated', 'shake') : null;
|
||||
return (
|
||||
<td className="react-bootstrap-table-editing-cell">
|
||||
<td
|
||||
className={ cs('react-bootstrap-table-editing-cell', className) }
|
||||
style={ style }
|
||||
>
|
||||
<TextEditor
|
||||
ref={ node => this.editor = node }
|
||||
defaultValue={ value }
|
||||
@ -126,11 +129,15 @@ EditingCell.propTypes = {
|
||||
column: PropTypes.object.isRequired,
|
||||
onUpdate: PropTypes.func.isRequired,
|
||||
onEscape: PropTypes.func.isRequired,
|
||||
timeToCloseMessage: PropTypes.number
|
||||
timeToCloseMessage: PropTypes.number,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object
|
||||
};
|
||||
|
||||
EditingCell.defaultProps = {
|
||||
timeToCloseMessage: Const.TIME_TO_CLOSE_MESSAGE
|
||||
timeToCloseMessage: Const.TIME_TO_CLOSE_MESSAGE,
|
||||
className: null,
|
||||
style: {}
|
||||
};
|
||||
|
||||
export default EditingCell;
|
||||
|
||||
@ -105,6 +105,8 @@ HeaderCell.propTypes = {
|
||||
sort: PropTypes.bool,
|
||||
sortFunc: PropTypes.func,
|
||||
editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
||||
editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
validator: PropTypes.func
|
||||
}).isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
|
||||
10
packages/react-bootstrap-table2/src/row.js
vendored
10
packages/react-bootstrap-table2/src/row.js
vendored
@ -53,11 +53,21 @@ const Row = (props) => {
|
||||
editable = column.editable(content, row, rowIndex, index);
|
||||
}
|
||||
if (rowIndex === editingRowIdx && index === editingColIdx) {
|
||||
let style = column.editCellStyle || {};
|
||||
let classes = column.editCellClasses;
|
||||
if (_.isFunction(column.editCellStyle)) {
|
||||
style = column.editCellStyle(content, row, rowIndex, index);
|
||||
}
|
||||
if (_.isFunction(column.editCellClasses)) {
|
||||
classes = column.editCellClasses(content, row, rowIndex, index);
|
||||
}
|
||||
return (
|
||||
<EditingCell
|
||||
key={ content }
|
||||
row={ row }
|
||||
column={ column }
|
||||
className={ classes }
|
||||
style={ style }
|
||||
{ ...rest }
|
||||
/>
|
||||
);
|
||||
|
||||
@ -75,6 +75,46 @@ describe('EditingCell', () => {
|
||||
expect(onEscape.callCount).toBe(1);
|
||||
});
|
||||
|
||||
describe('if style prop is defined', () => {
|
||||
const customStyle = { backgroundColor: 'red' };
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
style={ customStyle }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should render component with style successfully', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.find('td').prop('style')).toEqual(customStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if className prop is defined', () => {
|
||||
const className = 'test-class';
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
className={ className }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should render component with style successfully', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.hasClass(className)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if blurToSave prop is true', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
|
||||
@ -249,6 +249,122 @@ describe('Row', () => {
|
||||
expect(wrapper.find(EditingCell).length).toBe(1);
|
||||
expect(complexComponents.at(editingColIndex).type()).toEqual(EditingCell);
|
||||
});
|
||||
|
||||
describe('if column.editCellStyle defined as object', () => {
|
||||
const definedStyleColIndex = editingColIndex;
|
||||
|
||||
beforeEach(() => {
|
||||
columns[definedStyleColIndex].editCellStyle = { backgroundColor: 'red' };
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should also rendering EditingCell with correct style object', () => {
|
||||
expect(wrapper.find(EditingCell).length).toBe(1);
|
||||
expect(wrapper.find(EditingCell).props().style)
|
||||
.toEqual(columns[definedStyleColIndex].editCellStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if column.editCellStyle defined as function', () => {
|
||||
const definedStyleColIndex = editingColIndex;
|
||||
const customStyle = { backgroundColor: 'red' };
|
||||
let editCellStyleCallBack;
|
||||
|
||||
beforeEach(() => {
|
||||
editCellStyleCallBack = sinon.stub().returns(customStyle);
|
||||
columns[definedStyleColIndex].editCellStyle = editCellStyleCallBack;
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should calling custom column.editCellStyle callback correctly', () => {
|
||||
expect(editCellStyleCallBack.callCount).toBe(1);
|
||||
expect(
|
||||
editCellStyleCallBack.calledWith(
|
||||
row[columns[editingColIndex].dataField], row, rowIndex, editingColIndex)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should also rendering EditingCell with correct style object', () => {
|
||||
expect(wrapper.find(EditingCell).length).toBe(1);
|
||||
expect(wrapper.find(EditingCell).props().style).toEqual(customStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if column.editCellClasses defined as string', () => {
|
||||
const definedStyleColIndex = editingColIndex;
|
||||
|
||||
beforeEach(() => {
|
||||
columns[definedStyleColIndex].editCellClasses = 'custom-class';
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should also rendering EditingCell with correct class', () => {
|
||||
expect(wrapper.find(EditingCell).length).toBe(1);
|
||||
expect(wrapper.find(EditingCell).props().className)
|
||||
.toEqual(columns[definedStyleColIndex].editCellClasses);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if column.editCellClasses defined as function', () => {
|
||||
const definedStyleColIndex = editingColIndex;
|
||||
const customClass = 'custom-class';
|
||||
let editCellClassesCallBack;
|
||||
|
||||
beforeEach(() => {
|
||||
editCellClassesCallBack = sinon.stub().returns(customClass);
|
||||
columns[definedStyleColIndex].editCellClasses = editCellClassesCallBack;
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
cellEdit={ cellEdit }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should calling custom column.editCellStyle callback correctly', () => {
|
||||
expect(editCellClassesCallBack.callCount).toBe(1);
|
||||
expect(
|
||||
editCellClassesCallBack.calledWith(
|
||||
row[columns[editingColIndex].dataField], row, rowIndex, editingColIndex)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should also rendering EditingCell with correct class', () => {
|
||||
expect(wrapper.find(EditingCell).length).toBe(1);
|
||||
expect(wrapper.find(EditingCell).props().className).toEqual(customClass);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('and cellEdit.ridx is not match to current row index', () => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user