Skip to content

Commit 97e8007

Browse files
committed
Adding ability to provide custom editors
- On a column you can specify customEditor - pass in a react component class
1 parent 4a04f22 commit 97e8007

File tree

5 files changed

+178
-6
lines changed

5 files changed

+178
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/* eslint max-len: 0 */
2+
/* eslint no-alert: 0 */
3+
/* eslint guard-for-in: 0 */
4+
/* eslint no-unused-vars: 0 */
5+
import React from 'react';
6+
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
7+
8+
9+
const products = [];
10+
11+
const currencies = [ 'USD', 'GBP', 'EUR' ];
12+
const regions = [ 'North', 'South', 'East', 'West' ];
13+
14+
function addProducts(quantity) {
15+
const startId = products.length;
16+
for (let i = 0; i < quantity; i++) {
17+
const id = startId + i;
18+
products.push({
19+
id: id,
20+
name: 'Item name ' + id,
21+
price: {
22+
amount: 2100 + i,
23+
currency: currencies[i % currencies.length]
24+
},
25+
regions: regions.slice(0, (i % regions.length) + 1)
26+
});
27+
}
28+
}
29+
30+
addProducts(5);
31+
32+
const cellEditProp = {
33+
mode: 'click'
34+
};
35+
36+
class PriceEditor extends React.Component {
37+
constructor(props) {
38+
super(props);
39+
this.updateData = this.updateData.bind(this);
40+
this.state = { amount: props.defaultValue.amount, currency: props.defaultValue.currency };
41+
}
42+
focus() {
43+
this.refs.inputRef.focus();
44+
}
45+
updateData() {
46+
this.props.onUpdate({ amount: this.state.amount, currency: this.state.currency });
47+
}
48+
render() {
49+
return (
50+
<span>
51+
<input
52+
ref='inputRef'
53+
{ ...this.props }
54+
className={ ( this.props.editorClass || '') + ' form-control editor edit-text' }
55+
style={ { display: 'inline', width: '50%' } }
56+
type='text'
57+
value={ this.state.amount }
58+
onChange={ (ev) => { this.setState({ amount: parseInt(ev.currentTarget.value, 10) }); } } />
59+
<select
60+
value={ this.state.currency }
61+
onChange={ (ev) => { this.setState({ currency: ev.currentTarget.value }); } } >
62+
{ currencies.map(currency => (<option key={ currency } value={ currency }>{ currency }</option>)) }
63+
</select>
64+
<button
65+
className='btn btn-info btn-xs textarea-save-btn'
66+
onClick={ this.updateData }>
67+
save
68+
</button>
69+
</span>
70+
);
71+
}
72+
}
73+
74+
class RegionsEditor extends React.Component {
75+
constructor(props) {
76+
super(props);
77+
this.updateData = this.updateData.bind(this);
78+
this.state = { regions: props.defaultValue };
79+
this.onToggleRegion = this.onToggleRegion.bind(this);
80+
}
81+
focus() {
82+
}
83+
onToggleRegion(event) {
84+
const region = event.currentTarget.name;
85+
if (this.state.regions.indexOf(region) < 0) {
86+
this.setState({ regions: this.state.regions.concat([ region ]) });
87+
} else {
88+
this.setState({ regions: this.state.regions.filter(r => r !== region) });
89+
}
90+
}
91+
updateData() {
92+
this.props.onUpdate(this.state.regions);
93+
}
94+
render() {
95+
const regionCheckBoxes = regions.map(region => (
96+
<span key={ `span-${region}` }>
97+
<input
98+
type='checkbox'
99+
key={ region }
100+
name={ region }
101+
checked={ this.state.regions.indexOf(region) > -1 }
102+
onChange={ this.onToggleRegion } />
103+
<label key={ `label-${region}` } htmlFor={ region }>{ region }</label>
104+
</span>
105+
));
106+
return (
107+
<span ref='inputRef'>
108+
{ regionCheckBoxes }
109+
<button
110+
className='btn btn-info btn-xs textarea-save-btn'
111+
onClick={ this.updateData }>
112+
save
113+
</button>
114+
</span>
115+
);
116+
}
117+
}
118+
119+
function priceFormatter(cell, row) {
120+
return `<i class='glyphicon glyphicon-${cell.currency.toLowerCase()}'></i> ${cell.amount}`;
121+
}
122+
123+
const regionsFormatter = (cell, row) => (<span>{ (cell || []).join(',') }</span>);
124+
125+
export default class CustomCellEditTable extends React.Component {
126+
render() {
127+
return (
128+
<BootstrapTable data={ products } cellEdit={ cellEditProp }>
129+
<TableHeaderColumn dataField='id' isKey={ true }>Product ID</TableHeaderColumn>
130+
<TableHeaderColumn dataField='name'>Product Name</TableHeaderColumn>
131+
<TableHeaderColumn
132+
dataField='price'
133+
dataFormat={ priceFormatter }
134+
customEditor={ PriceEditor }>
135+
Product Price
136+
</TableHeaderColumn>
137+
<TableHeaderColumn
138+
dataField='regions'
139+
dataFormat={ regionsFormatter }
140+
customEditor={ RegionsEditor }>
141+
Regions
142+
</TableHeaderColumn>
143+
</BootstrapTable>
144+
);
145+
}
146+
}

examples/js/cell-edit/demo.js

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import DbClickToEditTable from './dbclick-to-edit-table';
55
import BlurToSaveTable from './blur-to-save-table';
66
import CellEditHookTable from './cell-edit-hook-table';
77
import NonEditableTable from './non-editable-table';
8+
import CustomCellEditTable from './custom-cell-edit-table';
89

910
class Demo extends React.Component {
1011
render() {
@@ -59,6 +60,15 @@ class Demo extends React.Component {
5960
</div>
6061
</div>
6162
</div>
63+
<div className='col-md-offset-1 col-md-8'>
64+
<div className='panel panel-default'>
65+
<div className='panel-heading'>Custom Cell Editor Example</div>
66+
<div className='panel-body'>
67+
<h5>Source in /examples/js/cell-edit/custom-cell-edit-table.js</h5>
68+
<CustomCellEditTable />
69+
</div>
70+
</div>
71+
</div>
6272
</div>
6373
);
6474
}

src/BootstrapTable.js

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class BootstrapTable extends Component {
124124
formatExtraData: column.props.formatExtraData,
125125
filterFormatted: column.props.filterFormatted,
126126
editable: column.props.editable,
127+
customEditor: column.props.customEditor,
127128
hidden: column.props.hidden,
128129
hiddenOnInsert: column.props.hiddenOnInsert,
129130
searchable: column.props.searchable,

src/TableBody.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ class TableBody extends Component {
5252
completeEdit={ this.handleCompleteEditCell }
5353
// add by bluespring for column editor customize
5454
editable={ editable }
55+
customEditor={ column.customEditor }
5556
format={ column.format ? format : false }
5657
key={ i }
5758
blurToSave={ this.props.cellEdit.blurToSave }
5859
rowIndex={ r }
59-
colIndex={ i }>
60-
{ fieldValue }
61-
</TableEditColumn>
60+
colIndex={ i }
61+
fieldValue={ fieldValue } />
6262
);
6363
} else {
6464
// add by bluespring for className customize

src/TableEditColumn.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class TableEditColumn extends Component {
4848
}
4949
}
5050

51+
handleCustomUpdate = value => {
52+
this.props.completeEdit(value, this.props.rowIndex, this.props.colIndex);
53+
}
54+
5155
validator(value) {
5256
const ts = this;
5357
if (ts.props.editable.validator) {
@@ -82,7 +86,7 @@ class TableEditColumn extends Component {
8286
}
8387

8488
render() {
85-
const { editable, format, children } = this.props;
89+
const { editable, format, fieldValue, customEditor } = this.props;
8690
const { shakeEditor } = this.state;
8791
const attr = {
8892
ref: 'inputRef',
@@ -93,9 +97,15 @@ class TableEditColumn extends Component {
9397
editable.placeholder && (attr.placeholder = editable.placeholder);
9498

9599
const editorClass = classSet({ 'animated': shakeEditor, 'shake': shakeEditor });
100+
const CustomEditor = customEditor;
101+
const cellEditor = CustomEditor ? <CustomEditor
102+
{...attr}
103+
defaultValue={ fieldValue || '' }
104+
onUpdate={ this.handleCustomUpdate }/> :
105+
editor(editable, attr, format, editorClass, fieldValue || '');
96106
return (
97107
<td ref='td' style={ { position: 'relative' } }>
98-
{ editor(editable, attr, format, editorClass, children || '') }
108+
{ cellEditor }
99109
<Notifier ref='notifier'/>
100110
</td>
101111
);
@@ -116,7 +126,12 @@ TableEditColumn.propTypes = {
116126
blurToSave: PropTypes.bool,
117127
editable: PropTypes.oneOfType([ PropTypes.bool, PropTypes.object ]),
118128
format: PropTypes.oneOfType([ PropTypes.bool, PropTypes.func ]),
119-
children: PropTypes.node
129+
fieldValue: PropTypes.oneOfType([
130+
PropTypes.string,
131+
PropTypes.bool,
132+
PropTypes.number,
133+
PropTypes.object
134+
])
120135
};
121136

122137

0 commit comments

Comments
 (0)