diff --git a/docs/README.md b/docs/README.md index d622a8848..9bc4ff181 100644 --- a/docs/README.md +++ b/docs/README.md @@ -39,11 +39,36 @@ * [onDataSizeChange](#onDataSizeChange) ### keyField(**required**) - [String] -Tells `react-bootstrap-table2` which column is unique. +Tells `react-bootstrap-table2` which column of the data is unique. This should be the name of a property that is unique for each item in your dataset ### data(**required**) - [Array] Provides data for your table. It accepts a single Array object. +Each item in this array is an object that represents a row in the table. Each "Row" object should have a key-value pair for each column in the table, whose key matches that column's dataField value. + +For example, if your column definitions look like: + +```js +columns = [ + { dataField: 'id', text: 'Id' }, + { dataField: 'name', text: 'Name' }, + { dataField: 'animal', text: 'Animal' }, +] +``` + +Then your data might look like: + +```js +data = [ + { id: 1, name: 'George', animal: 'Monkey' } + { id: 2, name: 'Jeffrey', animal: 'Giraffe' } + { id: 3, name: 'Alice', animal: 'Giraffe' } + { id: 4, name: 'Alice', animal: 'Tiger' } +] +``` + +And your "keyField" would be `id` + ### columns(**required**) - [Object] Accepts a single Array object, please see [columns definition](./columns.md) for more detail. diff --git a/packages/react-bootstrap-table2-example/examples/search/search-hook.js b/packages/react-bootstrap-table2-example/examples/search/search-hook.js new file mode 100644 index 000000000..3abbe3bca --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/search/search-hook.js @@ -0,0 +1,91 @@ +/* eslint react/prop-types: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const { SearchBar } = Search; +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit'; + +const { SearchBar } = Search; +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const afterSearch = (newResult) => { + console.log(newResult); +}; + + + { + props => ( +
+

Input something at below input field:

+ +
+ +
+ ) + } +
+`; + +const afterSearch = (newResult) => { + console.log(newResult); +}; + +export default () => ( +
+ + { + props => ( +
+

Input something at below input field:

+ +
+ +
+ ) + } +
+ { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 9bca826bf..757cbad18 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -197,6 +197,7 @@ import CustomePaginationWithSearch from 'examples/pagination/custom-page-list-wi import SearchTable from 'examples/search'; import ClearSearchButton from 'examples/search/clear-search-button'; import DefaultSearch from 'examples/search/default-search'; +import SearchHooks from 'examples/search/search-hook'; import DefaultCustomSearch from 'examples/search/default-custom-search'; import FullyCustomSearch from 'examples/search/fully-custom-search'; import SearchFormattedData from 'examples/search/search-formatted'; @@ -464,6 +465,7 @@ storiesOf('Table Search', module) .add('Clear Search Button', () => ) .add('Default Search Table', () => ) .add('Default Custom Search', () => ) + .add('Search Hooks', () => ) .add('Searchable Column', () => ) .add('Fully Custom Search', () => ) .add('Search Formatted Value', () => ) diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index 697aa9f99..70f45914f 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -2,7 +2,7 @@ `react-bootstrap-table2` separate the filter core code base to [`react-bootstrap-table2-filter`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-filter), so there's a little bit different when you use column filter than `react-bootstrap-table`. In the following, we are going to show you how to enable the column filter: -**[Live Demo For Column Filter](https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/gh-pages-src/storybook/index.html?selectedKind=Column%20Filter)** +**[Live Demo For Column Filter](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Column%20Filter)** **[API&Props Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/filter-props.html)** @@ -385,4 +385,4 @@ export default () => ( /> ); -``` \ No newline at end of file +``` diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index 7aad77bc3..924e00982 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -39,55 +39,36 @@ export const filterByNumber = _ => ( ) => ( data.filter((row) => { if (number === '' || !comparator) return true; - let valid = true; let cell = _.get(row, dataField); + if (customFilterValue) { cell = customFilterValue(cell, row); } switch (comparator) { case EQ: { - if (cell != number) { - valid = false; - } - break; + return cell == number; } case GT: { - if (cell <= number) { - valid = false; - } - break; + return cell > number; } case GE: { - if (cell < number) { - valid = false; - } - break; + return cell >= number; } case LT: { - if (cell >= number) { - valid = false; - } - break; + return cell < number; } case LE: { - if (cell > number) { - valid = false; - } - break; + return cell <= number; } case NE: { - if (cell == number) { - valid = false; - } - break; + return cell != number; } default: { console.error('Number comparator provided is not supported'); - break; + return true; } } - return valid; }) ); @@ -208,25 +189,19 @@ export const filterByArray = _ => ( }; export const filterFactory = _ => (filterType) => { - let filterFn; switch (filterType) { - case FILTER_TYPE.TEXT: - case FILTER_TYPE.SELECT: - filterFn = filterByText(_); - break; case FILTER_TYPE.MULTISELECT: - filterFn = filterByArray(_); - break; + return filterByArray(_); case FILTER_TYPE.NUMBER: - filterFn = filterByNumber(_); - break; + return filterByNumber(_); case FILTER_TYPE.DATE: - filterFn = filterByDate(_); - break; + return filterByDate(_); + case FILTER_TYPE.TEXT: + case FILTER_TYPE.SELECT: default: - filterFn = filterByText(_); + // Use `text` filter as default filter + return filterByText(_); } - return filterFn; }; export const filters = (data, columns, _) => (currFilters, clearFilters = {}) => { diff --git a/packages/react-bootstrap-table2-filter/test/context.test.js b/packages/react-bootstrap-table2-filter/test/context.test.js index eccef3063..248ed88d1 100644 --- a/packages/react-bootstrap-table2-filter/test/context.test.js +++ b/packages/react-bootstrap-table2-filter/test/context.test.js @@ -55,11 +55,13 @@ describe('FilterContext', () => { jest.fn().mockReturnValue(enableRemote), handleFilterChange ); + const filterOptions = {}; return ( diff --git a/packages/react-bootstrap-table2-toolkit/README.md b/packages/react-bootstrap-table2-toolkit/README.md index 84b24445b..948f34eb6 100644 --- a/packages/react-bootstrap-table2-toolkit/README.md +++ b/packages/react-bootstrap-table2-toolkit/README.md @@ -80,6 +80,9 @@ Custom the style on input element. #### delay = [number] milionsecond for debounce user input. +#### srText = [string] +Customize the screen reader text for the search input. (Default: "Search this table") + ### Search Options #### defaultSearch - [string] @@ -141,6 +144,22 @@ If you want to search on the formatted data, you are supposed to enable this pro ``` +#### afterSearch - [Function] +After search done, this callback function will be called with newest result. + +```js + console.log(newResult) + } } +> + // ... + +``` + ### Clear Search Button We have a built-in clear search function which allow user clear search status via clicking button: diff --git a/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js b/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js index 9bef75f32..fac666a8e 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js @@ -56,7 +56,8 @@ class SearchBar extends React.Component { className, style, placeholder, - tableId + tableId, + srText } = this.props; return ( @@ -64,13 +65,15 @@ class SearchBar extends React.Component { htmlFor={ `search-bar-${tableId}` } className="search-label" > - Search this table + + { srText } + this.input = n } id={ `search-bar-${tableId}` } type="text" style={ style } - aria-label="enter text you want to search" + aria-labelledby={ `search-bar-${tableId}-label` } onKeyUp={ () => this.onKeyup() } onChange={ this.onChangeValue } className={ `form-control ${className}` } @@ -89,7 +92,8 @@ SearchBar.propTypes = { style: PropTypes.object, delay: PropTypes.number, searchText: PropTypes.string, - tableId: PropTypes.string + tableId: PropTypes.string, + srText: PropTypes.string }; SearchBar.defaultProps = { @@ -98,7 +102,8 @@ SearchBar.defaultProps = { placeholder: 'Search', delay: 250, searchText: '', - tableId: '0' + tableId: '0', + srText: 'Search this table' }; export default SearchBar; diff --git a/packages/react-bootstrap-table2-toolkit/src/search/context.js b/packages/react-bootstrap-table2-toolkit/src/search/context.js index ec94da7a3..9f34c92ab 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/context.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/context.js @@ -9,6 +9,7 @@ import PropTypes from 'prop-types'; export default (options = { searchFormatted: false, + afterSearch: null, onColumnMatch: null }) => ( _, @@ -32,7 +33,7 @@ export default (options = { handleRemoteSearchChange(this.props.searchText); } else { initialData = this.search(props); - this.triggerListener(initialData); + this.triggerListener(initialData, true); } this.state = { data: initialData }; } @@ -41,7 +42,10 @@ export default (options = { return this.state.data; } - triggerListener(result) { + triggerListener(result, skipInit) { + if (options.afterSearch && !skipInit) { + options.afterSearch(result); + } if (this.props.dataChangeListener) { this.props.dataChangeListener.emit('filterChanged', result.length); } diff --git a/packages/react-bootstrap-table2/src/contexts/row-expand-context.js b/packages/react-bootstrap-table2/src/contexts/row-expand-context.js index fb1aed05a..7b7172a5e 100644 --- a/packages/react-bootstrap-table2/src/contexts/row-expand-context.js +++ b/packages/react-bootstrap-table2/src/contexts/row-expand-context.js @@ -23,13 +23,16 @@ class RowExpandProvider extends React.Component { UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.expandRow) { - const nextExpanded = nextProps.expandRow.expanded || this.state.expanded; + let nextExpanded = [...(nextProps.expandRow.expanded || this.state.expanded)]; + const { nonExpandable = [] } = nextProps.expandRow; + nextExpanded = nextExpanded.filter(rowId => !_.contains(nonExpandable, rowId)); const isClosing = this.state.expanded.reduce((acc, cur) => { if (!_.contains(nextExpanded, cur)) { acc.push(cur); } return acc; }, []); + this.setState(() => ({ expanded: nextExpanded, isClosing 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 f53753cff..ff20f1eca 100644 --- a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js +++ b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js @@ -92,7 +92,8 @@ export default class SelectionCell extends Component { mode: inputType, checked: selected, disabled, - rowIndex + rowIndex, + rowKey }) : ( ', () => { mode, checked: selected, disabled: wrapper.prop('disabled'), - rowIndex + rowIndex, + rowKey: 1 }); }); });