Skip to content

Commit ec742a4

Browse files
authored
Merge pull request #1149 from react-bootstrap-table/develop
20191109 release
2 parents be916d8 + 7138b68 commit ec742a4

File tree

14 files changed

+330
-27
lines changed

14 files changed

+330
-27
lines changed

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* [defaultSortDirection](#defaultSortDirection)
3333
* [pagination](#pagination)
3434
* [filter](#filter)
35+
* [filterPosition](filterPosition)
3536
* [onTableChange](#onTableChange)
3637
* [onDataSizeChange](#onDataSizeChange)
3738

@@ -329,6 +330,9 @@ Following is a shape of `newState`
329330
}
330331
```
331332

333+
### <a name='filterPosition'>filterPosition - [String]</a>
334+
Available value is `inline`, `top` and `bottom`, default is `inline`. This prop decide where `react-bootstrap-table` render column filter.
335+
332336
### <a name='onDataSizeChange'>onDataSizeChange - [Function]</a>
333337
This callback function will be called only when data size change by search/filter etc. This function have one argument which is an object contains below props:
334338

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
"webpack-dev-server": "2.7.1"
8181
},
8282
"dependencies": {
83-
"classnames": "2.2.5",
83+
"classnames": "^2.2.5",
8484
"prop-types": "15.5.10",
8585
"react": "16.4.0",
8686
"react-dom": "16.4.0",
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React from 'react';
2+
import BootstrapTable from 'react-bootstrap-table-next';
3+
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
4+
import Code from 'components/common/code-block';
5+
import { productsGenerator } from 'utils/common';
6+
7+
const products = productsGenerator(8);
8+
9+
const columns = [{
10+
dataField: 'id',
11+
text: 'Product ID'
12+
}, {
13+
dataField: 'name',
14+
text: 'Product Name',
15+
filter: textFilter()
16+
}, {
17+
dataField: 'price',
18+
text: 'Product Price',
19+
filter: textFilter()
20+
}];
21+
22+
const sourceCode1 = `\
23+
import BootstrapTable from 'react-bootstrap-table-next';
24+
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
25+
26+
const columns = [{
27+
dataField: 'id',
28+
text: 'Product ID',
29+
}, {
30+
dataField: 'name',
31+
text: 'Product Name',
32+
filter: textFilter()
33+
}, {
34+
dataField: 'price',
35+
text: 'Product Price',
36+
filter: textFilter()
37+
}];
38+
39+
<BootstrapTable
40+
keyField='id'
41+
data={ products }
42+
columns={ columns }
43+
filter={ filterFactory() }
44+
filterPosition="top"
45+
/>
46+
`;
47+
48+
const sourceCode2 = `\
49+
import BootstrapTable from 'react-bootstrap-table-next';
50+
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
51+
52+
const columns = [{
53+
dataField: 'id',
54+
text: 'Product ID',
55+
}, {
56+
dataField: 'name',
57+
text: 'Product Name',
58+
filter: textFilter()
59+
}, {
60+
dataField: 'price',
61+
text: 'Product Price',
62+
filter: textFilter()
63+
}];
64+
65+
<BootstrapTable
66+
keyField='id'
67+
data={ products }
68+
columns={ columns }
69+
filter={ filterFactory() }
70+
filterPosition="bottom"
71+
/>
72+
`;
73+
74+
export default () => (
75+
<div>
76+
<BootstrapTable
77+
keyField="id"
78+
data={ products }
79+
columns={ columns }
80+
filter={ filterFactory() }
81+
filterPosition="top"
82+
/>
83+
<Code>{ sourceCode1 }</Code>
84+
<BootstrapTable
85+
keyField="id"
86+
data={ products }
87+
columns={ columns }
88+
filter={ filterFactory() }
89+
filterPosition="bottom"
90+
/>
91+
<Code>{ sourceCode2 }</Code>
92+
</div>
93+
);

packages/react-bootstrap-table2-example/examples/column-filter/text-filter.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ const products = productsGenerator(8);
88

99
const columns = [{
1010
dataField: 'id',
11-
text: 'Product ID'
11+
text: 'Product ID',
12+
footer: 'hello'
1213
}, {
1314
dataField: 'name',
1415
text: 'Product Name',
16+
footer: 'hello',
1517
filter: textFilter()
1618
}, {
1719
dataField: 'price',
1820
text: 'Product Price',
21+
footer: 'hello',
1922
filter: textFilter()
2023
}];
2124

@@ -39,13 +42,20 @@ const columns = [{
3942
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
4043
`;
4144

45+
const selectRow = {
46+
mode: 'checkbox',
47+
clickToSelect: true
48+
};
49+
4250
export default () => (
4351
<div>
4452
<BootstrapTable
4553
keyField="id"
4654
data={ products }
4755
columns={ columns }
4856
filter={ filterFactory() }
57+
filterPosition="bottom"
58+
selectRow={ selectRow }
4959
/>
5060
<Code>{ sourceCode }</Code>
5161
</div>

packages/react-bootstrap-table2-example/stories/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import AdvanceCustomFilter from 'examples/column-filter/advance-custom-filter';
9292
import ClearAllFilters from 'examples/column-filter/clear-all-filters';
9393
import FilterHooks from 'examples/column-filter/filter-hooks';
9494
import CustomFilterLogic from 'examples/column-filter/custom-filter-logic';
95+
import FilterPosition from 'examples/column-filter/filter-position';
9596

9697
// work on rows
9798
import RowStyleTable from 'examples/rows/row-style';
@@ -314,6 +315,7 @@ storiesOf('Column Filter', module)
314315
.add('Number Filter with Default Value', () => <NumberFilterWithDefaultValue />)
315316
.add('Date Filter', () => <DateFilter />)
316317
.add('Date Filter with Default Value', () => <DateFilterWithDefaultValue />)
318+
.add('Filter Position', () => <FilterPosition />)
317319
.add('Custom Text Filter', () => <CustomTextFilter />)
318320
.add('Custom Select Filter', () => <CustomSelectFilter />)
319321
.add('Custom Number Filter', () => <CustomNumberFilter />)

packages/react-bootstrap-table2-filter/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,29 @@ Following properties is valid in `FILTER_TYPES`:
330330
* NUMBER
331331
* DATE
332332
* MULTISELECT
333+
334+
### Position
335+
Default filter is rendered inside the table column header, but you can choose to render them as a row by `filterPosition`:
336+
337+
#### Render in the top of table body
338+
339+
```js
340+
<BootstrapTable
341+
keyField='id'
342+
data={ products }
343+
columns={ columns }
344+
filter={ filterFactory() }
345+
filterPosition="top"
346+
/>
347+
```
348+
349+
#### Render in the bottom of table body
350+
```js
351+
<BootstrapTable
352+
keyField='id'
353+
data={ products }
354+
columns={ columns }
355+
filter={ filterFactory() }
356+
filterPosition="bottom"
357+
/>
358+
```

packages/react-bootstrap-table2/src/bootstrap-table.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
66
import cs from 'classnames';
77

88
import Header from './header';
9+
import Filters from './filters';
910
import Caption from './caption';
1011
import Body from './body';
1112
import Footer from './footer';
@@ -65,7 +66,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
6566
rowEvents,
6667
selectRow,
6768
expandRow,
68-
cellEdit
69+
cellEdit,
70+
filterPosition
6971
} = this.props;
7072

7173
const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses);
@@ -77,6 +79,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
7779
[bootstrap4 ? 'table-sm' : 'table-condensed']: condensed
7880
}, classes);
7981

82+
const hasFilters = columns.some(col => col.filter || col.filterRenderer);
83+
8084
const hasFooter = _.filter(columns, col => _.has(col, 'footer')).length > 0;
8185

8286
const tableCaption = (caption && <Caption>{ caption }</Caption>);
@@ -96,7 +100,19 @@ class BootstrapTable extends PropsBaseResolver(Component) {
96100
onExternalFilter={ this.props.onExternalFilter }
97101
selectRow={ selectRow }
98102
expandRow={ expandRow }
103+
filterPosition={ filterPosition }
99104
/>
105+
{hasFilters && filterPosition !== Const.FILTERS_POSITION_INLINE && (
106+
<Filters
107+
columns={ columns }
108+
className={ this.props.filtersClasses }
109+
onSort={ this.props.onSort }
110+
onFilter={ this.props.onFilter }
111+
currFilters={ this.props.currFilters }
112+
filterPosition={ this.props.filterPosition }
113+
onExternalFilter={ this.props.onExternalFilter }
114+
/>
115+
)}
100116
<Body
101117
data={ this.getData() }
102118
keyField={ keyField }
@@ -135,7 +151,7 @@ BootstrapTable.propTypes = {
135151
remote: PropTypes.oneOfType([PropTypes.bool, PropTypes.shape({
136152
pagination: PropTypes.bool
137153
})]),
138-
noDataIndication: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
154+
noDataIndication: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
139155
striped: PropTypes.bool,
140156
bordered: PropTypes.bool,
141157
hover: PropTypes.bool,
@@ -199,6 +215,12 @@ BootstrapTable.propTypes = {
199215
rowEvents: PropTypes.object,
200216
rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
201217
headerClasses: PropTypes.string,
218+
filtersClasses: PropTypes.string,
219+
filterPosition: PropTypes.oneOf([
220+
Const.FILTERS_POSITION_TOP,
221+
Const.FILTERS_POSITION_INLINE,
222+
Const.FILTERS_POSITION_BOTTOM
223+
]),
202224
footerClasses: PropTypes.string,
203225
defaultSorted: PropTypes.arrayOf(PropTypes.shape({
204226
dataField: PropTypes.string.isRequired,
@@ -240,7 +262,8 @@ BootstrapTable.defaultProps = {
240262
cellEdit: {
241263
mode: null,
242264
nonEditableRows: []
243-
}
265+
},
266+
filterPosition: Const.FILTERS_POSITION_INLINE
244267
};
245268

246269
export default BootstrapTable;

packages/react-bootstrap-table2/src/const.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ export default {
1212
TYPE_STRING: 'string',
1313
TYPE_NUMBER: 'number',
1414
TYPE_BOOLEAN: 'bool',
15-
TYPE_DATE: 'date'
15+
TYPE_DATE: 'date',
16+
FILTERS_POSITION_INLINE: 'inline',
17+
FILTERS_POSITION_TOP: 'top',
18+
FILTERS_POSITION_BOTTOM: 'bottom'
1619
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import _ from './utils';
4+
5+
const FiltersCell = (props) => {
6+
const {
7+
index, column, onExternalFilter,
8+
currFilters, onFilter
9+
} = props;
10+
const { filterRenderer, filter } = column;
11+
let filterElm;
12+
const cellAttrs = {};
13+
const cellStyle = {};
14+
cellAttrs.style = cellStyle;
15+
if (column.headerAlign) {
16+
cellStyle.textAlign = _.isFunction(column.headerAlign)
17+
? column.headerAlign(column, index)
18+
: column.headerAlign;
19+
}
20+
if (column.filterRenderer) {
21+
const onCustomFilter = onExternalFilter(column, filter.props.type);
22+
filterElm = filterRenderer(onCustomFilter, column);
23+
} else if (filter) {
24+
filterElm = (
25+
<filter.Filter
26+
{ ...filter.props }
27+
filterState={ currFilters[column.dataField] }
28+
onFilter={ onFilter }
29+
column={ column }
30+
/>
31+
);
32+
}
33+
return React.createElement('th', cellAttrs, filterElm);
34+
};
35+
36+
FiltersCell.propTypes = {
37+
index: PropTypes.number.isRequired,
38+
column: PropTypes.object.isRequired,
39+
currFilters: PropTypes.object.isRequired,
40+
onFilter: PropTypes.func,
41+
onExternalFilter: PropTypes.func
42+
};
43+
44+
FiltersCell.defaultProps = {
45+
onFilter: () => { },
46+
onExternalFilter: () => { }
47+
};
48+
49+
export default FiltersCell;

0 commit comments

Comments
 (0)