diff --git a/docs/README.md b/docs/README.md index 56f1fa3..3fc1c58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,6 +27,7 @@ * [rowStyle](#rowStyle) * [rowClasses](#rowClasses) * [rowEvents](#rowEvents) +* [hiddenRows](#hiddenRows) * [defaultSorted](#defaultSorted) * [defaultSortDirection](#defaultSortDirection) * [pagination](#pagination) @@ -181,6 +182,14 @@ const rowEvents = { ``` +### hiddenRows - [Array] +Hide rows, this props accept an array of row keys: + +```js +const hiddenRows = [1, 4]; + +``` + ### defaultSorted - [Array] `defaultSorted` accept an object array which allow you to define the default sort columns when first render. diff --git a/docs/row-expand.md b/docs/row-expand.md index 8afb1aa..ce710de 100644 --- a/docs/row-expand.md +++ b/docs/row-expand.md @@ -92,13 +92,16 @@ const expandRow = { ``` ### expandRow.expandColumnRenderer - [Function] -Provide a callback function which allow you to custom the expand indicator. This callback only have one argument which is an object and contain one property `expanded` which indicate if current row is expanded +Provide a callback function which allow you to custom the expand indicator. This callback only have one argument which is an object and contain these properties: +* `expanded`: If current row is expanded or not +* `rowKey`: Current row key +* `expandable`: If currnet row is expandable or not ```js const expandRow = { renderer: (row) => ... - expandColumnRenderer: ({ expanded }) => ( + expandColumnRenderer: ({ expanded, rowKey, expandable }) => ( // .... ) }; diff --git a/packages/react-bootstrap-table2-example/examples/row-expand/custom-expand-column.js b/packages/react-bootstrap-table2-example/examples/row-expand/custom-expand-column.js index 067046d..507bcf2 100644 --- a/packages/react-bootstrap-table2-example/examples/row-expand/custom-expand-column.js +++ b/packages/react-bootstrap-table2-example/examples/row-expand/custom-expand-column.js @@ -1,4 +1,5 @@ /* eslint react/prop-types: 0 */ +/* eslint no-unused-vars: 0 */ import React from 'react'; import BootstrapTable from 'react-bootstrap-table-next'; @@ -33,7 +34,7 @@ const expandRow = { } return +; }, - expandColumnRenderer: ({ expanded }) => { + expandColumnRenderer: ({ expanded, rowKey, expandable }) => { if (expanded) { return ( - diff --git a/packages/react-bootstrap-table2-example/examples/row-expand/non-expandable-rows.js b/packages/react-bootstrap-table2-example/examples/row-expand/non-expandable-rows.js index 6d1ef32..44acdf9 100644 --- a/packages/react-bootstrap-table2-example/examples/row-expand/non-expandable-rows.js +++ b/packages/react-bootstrap-table2-example/examples/row-expand/non-expandable-rows.js @@ -25,6 +25,7 @@ const expandRow = {

expandRow.renderer callback will pass the origin row object to you

), + showExpandColumn: true, nonExpandable: [1, 3] }; @@ -50,6 +51,7 @@ const expandRow = {

expandRow.renderer callback will pass the origin row object to you

), + showExpandColumn: true, nonExpandable: [1, 3] }; diff --git a/packages/react-bootstrap-table2-example/examples/rows/row-hidden.js b/packages/react-bootstrap-table2-example/examples/rows/row-hidden.js new file mode 100644 index 0000000..c200a7b --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/rows/row-hidden.js @@ -0,0 +1,57 @@ +/* eslint no-unused-vars: 0 */ +/* eslint no-console: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +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, row, rowIndex) => { + console.log(`clicked on row with index: ${rowIndex}`); + }, + onMouseEnter: (e, row, rowIndex) => { + console.log(`enter on row with index: ${rowIndex}`); + } +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const hiddenRowKeys = [1, 3]; + + +`; + +const hiddenRowKeys = [1, 3]; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 2757280..fe2eecd 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -79,6 +79,7 @@ import ClearAllFilters from 'examples/column-filter/clear-all-filters'; import RowStyleTable from 'examples/rows/row-style'; import RowClassTable from 'examples/rows/row-class'; import RowEventTable from 'examples/rows/row-event'; +import RowHiddenTable from 'examples/rows/row-hidden'; // table sort import EnableSortTable from 'examples/sort/enable-sort-table'; @@ -271,6 +272,7 @@ storiesOf('Work on Rows', module) .addDecorator(bootstrapStyle()) .add('Customize Row Style', () => ) .add('Customize Row Class', () => ) + .add('Hide Rows', () => ) .add('Row Event', () => ); storiesOf('Sort Table', module) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index c23eb91..8bcd7c1 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -21,7 +21,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { // Exposed APIs getData() { - return this.props.data; + return this.visibleRows(); } render() { @@ -39,7 +39,6 @@ class BootstrapTable extends PropsBaseResolver(Component) { renderTable() { const { - data, columns, keyField, tabIndexCell, @@ -88,7 +87,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { expandRow={ expandRow } /> { + if (this.props.expandRow.nonExpandable.includes(rowKey)) { + return; + } const { data, keyField, expandRow: { onExpand, onlyOneExpanding } } = this.props; let currExpanded = [...this.state.expanded]; @@ -73,6 +76,7 @@ class RowExpandProvider extends React.Component { @@ -15,4 +16,13 @@ export default ExtendBase => isEmpty() { return this.props.data.length === 0; } + + visibleRows() { + const { data, hiddenRows, keyField } = this.props; + if (!hiddenRows || hiddenRows.length === 0) return data; + return data.filter((row) => { + const key = _.get(row, keyField); + return !hiddenRows.includes(key); + }); + } }; diff --git a/packages/react-bootstrap-table2/src/row-expand/expand-cell.js b/packages/react-bootstrap-table2/src/row-expand/expand-cell.js index 5aa33f5..4b5903d 100644 --- a/packages/react-bootstrap-table2/src/row-expand/expand-cell.js +++ b/packages/react-bootstrap-table2/src/row-expand/expand-cell.js @@ -10,6 +10,7 @@ export default class ExpandCell extends Component { static propTypes = { rowKey: PropTypes.any, expanded: PropTypes.bool.isRequired, + expandable: PropTypes.bool.isRequired, onRowExpand: PropTypes.func.isRequired, expandColumnRenderer: PropTypes.func, rowIndex: PropTypes.number, @@ -38,7 +39,7 @@ export default class ExpandCell extends Component { } render() { - const { expanded, expandColumnRenderer, tabIndex } = this.props; + const { expanded, expandable, expandColumnRenderer, tabIndex, rowKey } = this.props; const attrs = {}; if (tabIndex !== -1) attrs.tabIndex = tabIndex; @@ -46,8 +47,10 @@ export default class ExpandCell extends Component { { expandColumnRenderer ? expandColumnRenderer({ - expanded - }) : (expanded ? '(-)' : '(+)') + expandable, + expanded, + rowKey + }) : (expandable ? (expanded ? '(-)' : '(+)') : '') } ); diff --git a/packages/react-bootstrap-table2/src/row/aggregate-row.js b/packages/react-bootstrap-table2/src/row/aggregate-row.js index 32c997a..dfba8b5 100644 --- a/packages/react-bootstrap-table2/src/row/aggregate-row.js +++ b/packages/react-bootstrap-table2/src/row/aggregate-row.js @@ -31,6 +31,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co if ( this.props.selected !== nextProps.selected || this.props.expanded !== nextProps.expanded || + this.props.expandable !== nextProps.expandable || this.props.selectable !== nextProps.selectable || this.shouldUpdatedBySelfProps(nextProps) ) { @@ -54,6 +55,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co selectRow, expandRow, expanded, + expandable, selected, selectable, visibleColumnSize, @@ -84,6 +86,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co rowKey={ key } rowIndex={ rowIndex } expanded={ expanded } + expandable={ expandable } tabIndex={ tabIndexCell ? tabIndexStart++ : -1 } /> ) : null diff --git a/packages/react-bootstrap-table2/test/props-resolver/index.test.js b/packages/react-bootstrap-table2/test/props-resolver/index.test.js index 4543041..8c3d256 100644 --- a/packages/react-bootstrap-table2/test/props-resolver/index.test.js +++ b/packages/react-bootstrap-table2/test/props-resolver/index.test.js @@ -25,6 +25,51 @@ describe('TableResolver', () => { const BootstrapTableMock = extendTo(ExtendBase); let wrapper; + describe('visibleRows', () => { + describe('if hiddenRows prop is not existing', () => { + beforeEach(() => { + const mockElement = React.createElement(BootstrapTableMock, { + data, columns, keyField + }, null); + wrapper = shallow(mockElement); + }); + + it('should return correct data', () => { + expect(wrapper.instance().visibleRows()).toEqual(data); + }); + }); + + describe('if hiddenRows prop is an empty array', () => { + beforeEach(() => { + const mockElement = React.createElement(BootstrapTableMock, { + data, columns, keyField, hiddenRows: [] + }, null); + wrapper = shallow(mockElement); + }); + + it('should return correct data', () => { + expect(wrapper.instance().visibleRows()).toEqual(data); + }); + }); + + describe('if hiddenRows prop is not an empty array', () => { + const hiddenRows = [1]; + + beforeEach(() => { + const mockElement = React.createElement(BootstrapTableMock, { + data, columns, keyField, hiddenRows + }, null); + wrapper = shallow(mockElement); + }); + + it('should return correct data', () => { + const result = wrapper.instance().visibleRows(); + expect(result).toHaveLength(data.length - hiddenRows.length); + expect(result).toEqual(data.filter(d => !hiddenRows.includes(d.id))); + }); + }); + }); + describe('validateProps', () => { describe('if keyField is defined and columns is all visible', () => { beforeEach(() => {