diff --git a/docs/row-selection.md b/docs/row-selection.md
index 832ef1d..0aa5f2c 100644
--- a/docs/row-selection.md
+++ b/docs/row-selection.md
@@ -15,6 +15,8 @@ The following are available properties in `selectRow`:
* [nonSelectable)](#nonSelectable)
* [clickToSelect)](#clickToSelect)
* [clickToEdit](#clickToEdit)
+* [onSelect](#onSelect)
+* [onSelectAll](#onSelectAll)
#### Optional
@@ -144,4 +146,29 @@ const selectRow = {
clickToSelect: true
clickToEdit: true
};
-```
\ No newline at end of file
+```
+
+# selectRow.onSelect - [Function]
+This callback function will be called when a row is select/unselect and pass following three arguments:
+`row`, `isSelect` and `rowIndex`.
+
+```js
+const selectRow = {
+ mode: 'checkbox',
+ onSelect: (row, isSelect, rowIndex) => {
+ // ...
+ }
+};
+```
+
+# selectRow.onSelectAll - [Function]
+This callback function will be called when select/unselect all and it only work when you configure [`selectRow.mode`](#mode) as `checkbox`.
+
+```js
+const selectRow = {
+ mode: 'checkbox',
+ onSelectAll: (isSelect, results) => {
+ // ...
+ }
+};
+```
diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/selection-hooks.js b/packages/react-bootstrap-table2-example/examples/row-selection/selection-hooks.js
new file mode 100644
index 0000000..fd94d6b
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/row-selection/selection-hooks.js
@@ -0,0 +1,66 @@
+
+/* eslint no-console: 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'
+}, {
+ dataField: 'price',
+ text: 'Product Price'
+}];
+
+const selectRow = {
+ mode: 'checkbox',
+ clickToSelect: true,
+ onSelect: (row, isSelect, rowIndex) => {
+ console.log(row.id);
+ console.log(isSelect);
+ console.log(rowIndex);
+ },
+ onSelectAll: (isSelect, rows) => {
+ console.log(isSelect);
+ console.log(rows);
+ }
+};
+
+const sourceCode = `\
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'price',
+ text: 'Product Price'
+}];
+
+const selectRow = {
+ mode: 'checkbox',
+ clickToSelect: true
+};
+
+
+`;
+
+export default () => (
+
+
+ { sourceCode }
+
+);
diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js
index 6598dd6..31a03c1 100644
--- a/packages/react-bootstrap-table2-example/stories/index.js
+++ b/packages/react-bootstrap-table2-example/stories/index.js
@@ -59,6 +59,7 @@ import SelectionStyleTable from 'examples/row-selection/selection-style';
import SelectionClassTable from 'examples/row-selection/selection-class';
import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows';
import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor';
+import SelectionHooks from 'examples/row-selection/selection-hooks';
// css style
import 'bootstrap/dist/css/bootstrap.min.css';
@@ -126,4 +127,5 @@ storiesOf('Row Selection', module)
.add('Selection Style', () => )
.add('Selection Class', () => )
.add('Selection Background Color', () => )
- .add('Not Selectabled Rows', () => );
+ .add('Not Selectabled Rows', () => )
+ .add('Selection Hooks', () => );
diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js
index 11530c8..bcbf5cf 100644
--- a/packages/react-bootstrap-table2/src/bootstrap-table.js
+++ b/packages/react-bootstrap-table2/src/bootstrap-table.js
@@ -130,6 +130,8 @@ BootstrapTable.propTypes = {
mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired,
clickToSelect: PropTypes.bool,
clickToEdit: PropTypes.bool,
+ onSelect: PropTypes.func,
+ onSelectAll: PropTypes.func,
style: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
classes: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
nonSelectable: PropTypes.array,
diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js
index fa41f3a..bc7e0c5 100644
--- a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js
+++ b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js
@@ -12,7 +12,8 @@ export default class SelectionCell extends Component {
rowKey: PropTypes.any,
selected: PropTypes.bool,
onRowSelect: PropTypes.func,
- disabled: PropTypes.bool
+ disabled: PropTypes.bool,
+ rowIndex: PropTypes.number
}
constructor() {
@@ -32,7 +33,8 @@ export default class SelectionCell extends Component {
rowKey,
selected,
onRowSelect,
- disabled
+ disabled,
+ rowIndex
} = this.props;
if (disabled) return;
@@ -41,7 +43,7 @@ export default class SelectionCell extends Component {
? true
: !selected;
- onRowSelect(rowKey, checked);
+ onRowSelect(rowKey, checked, rowIndex);
}
render() {
diff --git a/packages/react-bootstrap-table2/src/row-selection/wrapper.js b/packages/react-bootstrap-table2/src/row-selection/wrapper.js
index dad9d6e..0e6b1c7 100644
--- a/packages/react-bootstrap-table2/src/row-selection/wrapper.js
+++ b/packages/react-bootstrap-table2/src/row-selection/wrapper.js
@@ -21,8 +21,8 @@ class RowSelectionWrapper extends Component {
* @param {String} rowKey - row key of what was selected.
* @param {Boolean} checked - next checked status of input button.
*/
- handleRowSelect(rowKey, checked) {
- const { selectRow: { mode }, store } = this.props;
+ handleRowSelect(rowKey, checked, rowIndex) {
+ const { selectRow: { mode, onSelect }, store } = this.props;
const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...store.getSelectedRowKeys()];
@@ -37,6 +37,11 @@ class RowSelectionWrapper extends Component {
store.setSelectedRowKeys(currSelected);
+ if (onSelect) {
+ const row = store.getRowByRowId(rowKey);
+ onSelect(row, checked, rowIndex);
+ }
+
this.setState(() => ({
selectedRowKeys: currSelected
}));
@@ -47,19 +52,26 @@ class RowSelectionWrapper extends Component {
* @param {Boolean} option - customized result for all rows selection
*/
handleAllRowsSelect(option) {
- const { store, selectRow } = this.props;
- const selected = store.isAnySelectedRow(selectRow.nonSelectable);
+ const { store, selectRow: {
+ onSelectAll,
+ nonSelectable
+ } } = this.props;
+ const selected = store.isAnySelectedRow(nonSelectable);
// set next status of all row selected by store.selected or customizing by user.
const result = option || !selected;
const currSelected = result ?
- store.selectAllRows(selectRow.nonSelectable) :
- store.cleanSelectedRows(selectRow.nonSelectable);
+ store.selectAllRows(nonSelectable) :
+ store.cleanSelectedRows(nonSelectable);
store.setSelectedRowKeys(currSelected);
+ if (onSelectAll) {
+ onSelectAll(result, store.getSelectedRows());
+ }
+
this.setState(() => ({
selectedRowKeys: currSelected
}));
diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js
index 23a8cf2..a53682e 100644
--- a/packages/react-bootstrap-table2/src/row.js
+++ b/packages/react-bootstrap-table2/src/row.js
@@ -21,6 +21,7 @@ class Row extends Component {
selected,
keyField,
selectable,
+ rowIndex,
selectRow: {
onRowSelect,
clickToEdit
@@ -33,12 +34,12 @@ class Row extends Component {
this.clickNum += 1;
_.debounce(() => {
if (this.clickNum === 1) {
- onRowSelect(key, !selected);
+ onRowSelect(key, !selected, rowIndex);
}
this.clickNum = 0;
}, Const.DELAY_FOR_DBCLICK)();
} else {
- onRowSelect(key, !selected);
+ onRowSelect(key, !selected, rowIndex);
}
}
}
@@ -83,6 +84,7 @@ class Row extends Component {
diff --git a/packages/react-bootstrap-table2/src/store/base.js b/packages/react-bootstrap-table2/src/store/base.js
index eb435d1..509dc63 100644
--- a/packages/react-bootstrap-table2/src/store/base.js
+++ b/packages/react-bootstrap-table2/src/store/base.js
@@ -50,6 +50,10 @@ export default class Store {
this.selected = selectedKeys;
}
+ getSelectedRows() {
+ return this.selected.map(k => this.getRowByRowId(k));
+ }
+
getSelectedRowKeys() {
return this.selected;
}
diff --git a/packages/react-bootstrap-table2/test/body.test.js b/packages/react-bootstrap-table2/test/body.test.js
index 717e34e..2e98068 100644
--- a/packages/react-bootstrap-table2/test/body.test.js
+++ b/packages/react-bootstrap-table2/test/body.test.js
@@ -318,7 +318,7 @@ describe('Body', () => {
it('should calling selectRow.bgColor callback correctly', () => {
expect(bgColorCallBack.calledOnce).toBeTruthy();
- expect(bgColorCallBack.calledWith(data[0]), 1);
+ expect(bgColorCallBack.calledWith(data[0]), 1).toBeTruthy();
});
it('should render Row component with correct style.backgroundColor prop', () => {
diff --git a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js
index 5c92145..bcb5799 100644
--- a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js
+++ b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js
@@ -6,6 +6,7 @@ import SelectionCell from '../../src/row-selection/selection-cell';
describe('', () => {
const mode = 'checkbox';
+ const rowIndex = 1;
let wrapper;
@@ -56,6 +57,7 @@ describe('', () => {
selected
rowKey={ rowKey }
mode={ mode }
+ rowIndex={ rowIndex }
onRowSelect={ mockOnRowSelect }
/>
);
@@ -69,7 +71,7 @@ describe('', () => {
it('should calling onRowSelect callback correctly', () => {
expect(mockOnRowSelect.calledOnce).toBe(true);
expect(
- mockOnRowSelect.calledWith(rowKey, !selected)
+ mockOnRowSelect.calledWith(rowKey, !selected, rowIndex)
).toBe(true);
});
});
@@ -81,6 +83,7 @@ describe('', () => {
selected
rowKey={ rowKey }
mode={ mode }
+ rowIndex={ rowIndex }
onRowSelect={ mockOnRowSelect }
disabled
/>
@@ -104,6 +107,7 @@ describe('', () => {
selected
rowKey={ rowKey }
mode="radio"
+ rowIndex={ rowIndex }
onRowSelect={ mockOnRowSelect }
/>
);
@@ -113,12 +117,12 @@ describe('', () => {
// first click
wrapper.find('td').simulate('click');
expect(mockOnRowSelect.callCount).toBe(1);
- expect(mockOnRowSelect.calledWith(rowKey, true)).toBe(true);
+ expect(mockOnRowSelect.calledWith(rowKey, true, rowIndex)).toBe(true);
// second click
wrapper.find('td').simulate('click');
expect(mockOnRowSelect.callCount).toBe(2);
- expect(mockOnRowSelect.calledWith(rowKey, true)).toBe(true);
+ expect(mockOnRowSelect.calledWith(rowKey, true, rowIndex)).toBe(true);
});
});
@@ -128,6 +132,7 @@ describe('', () => {
);
@@ -138,13 +143,13 @@ describe('', () => {
wrapper.setProps({ selected: true });
wrapper.find('td').simulate('click');
expect(mockOnRowSelect.callCount).toBe(1);
- expect(mockOnRowSelect.calledWith(rowKey, false)).toBe(true);
+ expect(mockOnRowSelect.calledWith(rowKey, false, rowIndex)).toBe(true);
// second click
wrapper.setProps({ selected: false });
wrapper.find('td').simulate('click');
expect(mockOnRowSelect.callCount).toBe(2);
- expect(mockOnRowSelect.calledWith(rowKey, true)).toBe(true);
+ expect(mockOnRowSelect.calledWith(rowKey, true, rowIndex)).toBe(true);
});
});
});
@@ -158,6 +163,7 @@ describe('', () => {
);
@@ -176,6 +182,7 @@ describe('', () => {
diff --git a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js
index 9ab18b6..ed5c858 100644
--- a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js
+++ b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js
@@ -1,4 +1,5 @@
import React from 'react';
+import sinon from 'sinon';
import { shallow } from 'enzyme';
import Store from '../../src/store/base';
@@ -28,6 +29,8 @@ describe('RowSelectionWrapper', () => {
mode: 'radio'
};
+ const rowIndex = 1;
+
const keyField = 'id';
const store = new Store({ data, keyField });
@@ -64,10 +67,10 @@ describe('RowSelectionWrapper', () => {
const secondSelectedRow = data[1][keyField];
it('call handleRowSelect function should seting correct state.selectedRowKeys', () => {
- wrapper.instance().handleRowSelect(firstSelectedRow);
+ wrapper.instance().handleRowSelect(firstSelectedRow, rowIndex);
expect(wrapper.state('selectedRowKeys')).toEqual([firstSelectedRow]);
- wrapper.instance().handleRowSelect(secondSelectedRow);
+ wrapper.instance().handleRowSelect(secondSelectedRow, rowIndex);
expect(wrapper.state('selectedRowKeys')).toEqual([secondSelectedRow]);
});
});
@@ -90,16 +93,16 @@ describe('RowSelectionWrapper', () => {
});
it('call handleRowSelect function should seting correct state.selectedRowKeys', () => {
- wrapper.instance().handleRowSelect(firstSelectedRow, true);
+ wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex);
expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([firstSelectedRow]));
- wrapper.instance().handleRowSelect(secondSelectedRow, true);
+ wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex);
expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow]));
- wrapper.instance().handleRowSelect(firstSelectedRow, false);
+ wrapper.instance().handleRowSelect(firstSelectedRow, false, rowIndex);
expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([secondSelectedRow]));
- wrapper.instance().handleRowSelect(secondSelectedRow, false);
+ wrapper.instance().handleRowSelect(secondSelectedRow, false, rowIndex);
expect(wrapper.state('selectedRowKeys')).toEqual([]);
});
@@ -119,4 +122,61 @@ describe('RowSelectionWrapper', () => {
expect(wrapper.state('selectedRowKeys')).toEqual([]);
});
});
+
+ describe('when selectRow.onSelect is defined', () => {
+ const selectedRow = data[0][keyField];
+ const onSelectCallBack = sinon.stub();
+
+ beforeEach(() => {
+ selectRow.mode = 'checkbox';
+ selectRow.onSelect = onSelectCallBack;
+ wrapper = shallow(
+
+ );
+ });
+
+ it('selectRow.onSelect callback should be called correctly when calling handleRowSelect function', () => {
+ wrapper.instance().handleRowSelect(selectedRow, true, rowIndex);
+ expect(onSelectCallBack.callCount).toEqual(1);
+ expect(onSelectCallBack.calledWith(data[0], true, rowIndex)).toBeTruthy();
+
+ wrapper.instance().handleRowSelect(selectedRow, false, rowIndex);
+ expect(onSelectCallBack.callCount).toEqual(2);
+ expect(onSelectCallBack.calledWith(data[0], false, rowIndex)).toBeTruthy();
+ });
+ });
+
+ describe('when selectRow.onSelectAll is defined', () => {
+ const onSelectAllCallBack = sinon.stub();
+
+ beforeEach(() => {
+ selectRow.mode = 'checkbox';
+ selectRow.onSelectAll = onSelectAllCallBack;
+ wrapper = shallow(
+
+ );
+ });
+
+ it('selectRow.onSelect callback should be called correctly when calling handleRowSelect function', () => {
+ wrapper.instance().handleAllRowsSelect();
+ expect(onSelectAllCallBack.callCount).toEqual(1);
+ expect(onSelectAllCallBack.calledWith(true, data)).toBeTruthy();
+
+ wrapper.instance().handleAllRowsSelect();
+ expect(onSelectAllCallBack.callCount).toEqual(2);
+ expect(onSelectAllCallBack.calledWith(false, [])).toBeTruthy();
+ });
+ });
});
diff --git a/packages/react-bootstrap-table2/test/row.test.js b/packages/react-bootstrap-table2/test/row.test.js
index f720ee7..84241e7 100644
--- a/packages/react-bootstrap-table2/test/row.test.js
+++ b/packages/react-bootstrap-table2/test/row.test.js
@@ -605,7 +605,7 @@ describe('Row', () => {
});
it('should calling selectRow.onRowSelect with correct argument', () => {
- expect(onRowSelectCallBack.calledWith(row[keyField], false)).toBeTruthy();
+ expect(onRowSelectCallBack.calledWith(row[keyField], false, rowIndex)).toBeTruthy();
});
});
@@ -636,7 +636,7 @@ describe('Row', () => {
});
it('should calling selectRow.onRowSelect with correct argument', () => {
- expect(onRowSelectCallBack.calledWith(row[keyField], true)).toBeTruthy();
+ expect(onRowSelectCallBack.calledWith(row[keyField], true, rowIndex)).toBeTruthy();
});
});
});
diff --git a/packages/react-bootstrap-table2/test/store/base.test.js b/packages/react-bootstrap-table2/test/store/base.test.js
index 716a350..7bfb8f6 100644
--- a/packages/react-bootstrap-table2/test/store/base.test.js
+++ b/packages/react-bootstrap-table2/test/store/base.test.js
@@ -87,6 +87,31 @@ describe('Store Base', () => {
});
});
+ describe('getSelectedRows', () => {
+ const selected = [1, 4];
+ beforeEach(() => {
+ store.setSelectedRowKeys(selected);
+ });
+
+ it('should return all selected rows by store.selected', () => {
+ const result = store.getSelectedRows();
+ expect(result).toBeDefined();
+ expect(result.length).toEqual(2);
+ result.forEach((r) => {
+ expect(r).toBeDefined();
+ expect(selected.includes(r[store.keyField])).toBeTruthy();
+ });
+ });
+ });
+
+ describe('setSelectedRowKeys', () => {
+ const selected = [1, 4];
+ it('should set store.selected correctly', () => {
+ store.setSelectedRowKeys(selected);
+ expect(store.getSelectedRowKeys()).toEqual(selected);
+ });
+ });
+
describe('edit', () => {
it('should update a specified field correctly', () => {
const newValue = 'newValue';