diff --git a/docs/README.md b/docs/README.md index aab6265..fb53620 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,6 +17,7 @@ * [selectRow](#selectRow) * [rowStyle](#rowStyle) * [rowClasses](#rowClasses) +* [rowEvents](#rowEvents) * [defaultSorted](#defaultSorted) ### keyField(**required**) - [String] @@ -50,7 +51,7 @@ Makes table rows selectable, please see [selectRow definition](./row-selection.m Custom the style of table rows: ```js - + ``` This prop also accept a callback function for flexible to custom row style: @@ -60,14 +61,14 @@ const rowStyle = (row, rowIndex) => { return { ... }; }; - + ``` ### rowClasses = [String | Function] Custom the style of table rows: ```js - + ``` This prop also accept a callback function for flexible to custom row style: @@ -77,7 +78,19 @@ const rowClasses = (row, rowIndex) => { return 'custom-row-class'; }; - + +``` + +### rowEvents - [Object] +Custom the events on row: + +```js +const rowEvents = { + onClick: (e) => { + .... + } +}; + ``` ### defaultSorted - [Array] diff --git a/packages/react-bootstrap-table2-example/examples/rows/row-event.js b/packages/react-bootstrap-table2-example/examples/rows/row-event.js new file mode 100644 index 0000000..1ec5022 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/rows/row-event.js @@ -0,0 +1,54 @@ +/* eslint no-unused-vars: 0 */ +/* 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 rowEvents = { + onClick: (e) => { + console.log('click on row'); + } +}; + +const sourceCode = `\ +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const rowEvents = { + onClick: (e) => { + console.log('click on row'); + } +}; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index c267778..c97b373 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -35,6 +35,7 @@ import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table'; // work on rows import RowStyleTable from 'examples/rows/row-style'; import RowClassTable from 'examples/rows/row-class'; +import RowEventTable from 'examples/rows/row-event'; // table sort import EnableSortTable from 'examples/sort/enable-sort-table'; @@ -109,7 +110,8 @@ storiesOf('Work on Header Columns', module) storiesOf('Work on Rows', module) .add('Customize Row Style', () => ) - .add('Customize Row Class', () => ); + .add('Customize Row Class', () => ) + .add('Row Event', () => ); storiesOf('Sort Table', module) .add('Enable Sort', () => ) diff --git a/packages/react-bootstrap-table2/src/body.js b/packages/react-bootstrap-table2/src/body.js index 85f4e35..b0182da 100644 --- a/packages/react-bootstrap-table2/src/body.js +++ b/packages/react-bootstrap-table2/src/body.js @@ -22,7 +22,8 @@ const Body = (props) => { selectRow, selectedRowKeys, rowStyle, - rowClasses + rowClasses, + rowEvents } = props; const { @@ -45,6 +46,7 @@ const Body = (props) => { ? selectedRowKeys.includes(key) : null; + const attrs = rowEvents || {}; let style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle; let classes = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses); if (selected) { @@ -84,6 +86,7 @@ const Body = (props) => { selectRow={ selectRow } style={ style } className={ classes } + attrs={ attrs } /> ); }); diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index b82d819..d77d47f 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -37,7 +37,8 @@ class BootstrapTable extends PropsBaseResolver(Component) { noDataIndication, caption, rowStyle, - rowClasses + rowClasses, + rowEvents } = this.props; const tableClass = cs('table', { @@ -87,6 +88,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { selectedRowKeys={ store.getSelectedRowKeys() } rowStyle={ rowStyle } rowClasses={ rowClasses } + rowEvents={ rowEvents } /> @@ -145,6 +147,7 @@ BootstrapTable.propTypes = { onRowSelect: PropTypes.func, onAllRowsSelect: PropTypes.func, rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), + rowEvents: PropTypes.object, rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), defaultSorted: PropTypes.arrayOf(PropTypes.shape({ dataField: PropTypes.string.isRequired, diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index d08fbec..a39d965 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -15,7 +15,7 @@ class Row extends Component { this.handleRowClick = this.handleRowClick.bind(this); } - handleRowClick() { + handleRowClick(e) { const { row, selected, @@ -25,22 +25,31 @@ class Row extends Component { selectRow: { onRowSelect, clickToEdit - } + }, + cellEdit: { mode }, + attrs } = this.props; - const key = _.get(row, keyField); - if (selectable) { - const { cellEdit: { mode } } = this.props; - if (mode === Const.DBCLICK_TO_CELL_EDIT && clickToEdit) { - this.clickNum += 1; - _.debounce(() => { - if (this.clickNum === 1) { - onRowSelect(key, !selected, rowIndex); - } - this.clickNum = 0; - }, Const.DELAY_FOR_DBCLICK)(); - } else { + + const clickFn = () => { + if (attrs.onClick) { + attrs.onClick(e); + } + if (selectable) { + const key = _.get(row, keyField); onRowSelect(key, !selected, rowIndex); } + }; + + if (mode === Const.DBCLICK_TO_CELL_EDIT && clickToEdit) { + this.clickNum += 1; + _.debounce(() => { + if (this.clickNum === 1) { + clickFn(); + } + this.clickNum = 0; + }, Const.DELAY_FOR_DBCLICK)(); + } else { + clickFn(); } } @@ -52,6 +61,7 @@ class Row extends Component { rowIndex, className, style, + attrs, cellEdit, selected, selectRow, @@ -70,7 +80,7 @@ class Row extends Component { const key = _.get(row, keyField); const { clickToSelect, hideSelectColumn } = selectRow; - const trAttrs = {}; + const trAttrs = { ...attrs }; if (clickToSelect) { trAttrs.onClick = this.handleRowClick; } @@ -143,13 +153,15 @@ Row.propTypes = { rowIndex: PropTypes.number.isRequired, columns: PropTypes.array.isRequired, style: PropTypes.object, - className: PropTypes.string + className: PropTypes.string, + attrs: PropTypes.object }; Row.defaultProps = { editable: true, style: {}, - className: null + className: null, + attrs: {} }; export default Row; diff --git a/packages/react-bootstrap-table2/test/body.test.js b/packages/react-bootstrap-table2/test/body.test.js index 51176d6..5674b83 100644 --- a/packages/react-bootstrap-table2/test/body.test.js +++ b/packages/react-bootstrap-table2/test/body.test.js @@ -339,6 +339,30 @@ describe('Body', () => { }); }); + describe('when rowEvents prop is defined', () => { + const rowEvents = { onClick: sinon.stub() }; + + describe('and it is a string', () => { + beforeEach(() => { + wrapper = shallow( + ); + }); + + it('should rendering Row component with correct attrs prop', () => { + const rows = wrapper.find(Row); + rows.forEach((row) => { + expect(row.props().attrs).toEqual(rowEvents); + }); + }); + }); + }); + describe('when cellEdit.nonEditableRows props is defined', () => { const nonEditableRows = [data[1].id]; const cellEdit = { diff --git a/packages/react-bootstrap-table2/test/row.test.js b/packages/react-bootstrap-table2/test/row.test.js index 10555bc..de8f5c5 100644 --- a/packages/react-bootstrap-table2/test/row.test.js +++ b/packages/react-bootstrap-table2/test/row.test.js @@ -84,7 +84,7 @@ describe('Row', () => { />); }); - it('should render component with style successfully', () => { + it('should render component with className successfully', () => { expect(wrapper.length).toBe(1); expect(wrapper.hasClass(className)).toBe(true); }); @@ -442,6 +442,27 @@ describe('Row', () => { }); }); + describe('when attrs prop is defined', () => { + const customClickCallBack = sinon.stub(); + const attrs = { 'data-index': 1, onClick: customClickCallBack }; + beforeEach(() => { + wrapper = shallow( + ); + }); + + it('should render component with correct attributes', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.prop('data-index')).toBe(attrs['data-index']); + expect(wrapper.prop('onClick')).toBeDefined(); + }); + }); + describe('when selectRow.mode is ROW_SELECT_DISABLED (row was un-selectable)', () => { beforeEach(() => { wrapper = shallow( @@ -697,5 +718,39 @@ describe('Row', () => { expect(wrapper.instance().clickNum).toEqual(2); }); }); + + describe('when attrs.onClick prop is defined', () => { + const customClickCallBack = sinon.stub(); + const attrs = { onClick: customClickCallBack }; + + beforeEach(() => { + onRowSelectCallBack = sinon.stub(); + selectRow = { + mode: 'checkbox', + clickToSelect: true, + onRowSelect: onRowSelectCallBack + }; + wrapper = shallow( + ); + wrapper.find('tr').simulate('click'); + }); + + it('should calling attrs.onClick callback', () => { + expect(customClickCallBack.callCount).toEqual(1); + }); + + it('should calling selectRow.onRowSelect callback', () => { + expect(onRowSelectCallBack.callCount).toEqual(1); + }); + }); }); });