Skip to content

Commit 909a6e2

Browse files
committed
close #1005
1 parent 83c9d69 commit 909a6e2

File tree

10 files changed

+192
-27
lines changed

10 files changed

+192
-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

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: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
6666
rowEvents,
6767
selectRow,
6868
expandRow,
69-
cellEdit
69+
cellEdit,
70+
filterPosition
7071
} = this.props;
7172

7273
const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses);
@@ -94,17 +95,21 @@ class BootstrapTable extends PropsBaseResolver(Component) {
9495
sortField={ this.props.sortField }
9596
sortOrder={ this.props.sortOrder }
9697
onSort={ this.props.onSort }
98+
onFilter={ this.props.onFilter }
99+
currFilters={ this.props.currFilters }
100+
onExternalFilter={ this.props.onExternalFilter }
97101
selectRow={ selectRow }
98102
expandRow={ expandRow }
103+
filterPosition={ filterPosition }
99104
/>
100-
{hasFilters && (
105+
{hasFilters && filterPosition !== Const.FILTERS_POSITION_INLINE && (
101106
<Filters
102107
columns={ columns }
103108
className={ this.props.filtersClasses }
104109
onSort={ this.props.onSort }
105110
onFilter={ this.props.onFilter }
106111
currFilters={ this.props.currFilters }
107-
position={ this.props.filtersPosition }
112+
filterPosition={ this.props.filterPosition }
108113
onExternalFilter={ this.props.onExternalFilter }
109114
/>
110115
)}
@@ -211,8 +216,9 @@ BootstrapTable.propTypes = {
211216
rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
212217
headerClasses: PropTypes.string,
213218
filtersClasses: PropTypes.string,
214-
filtersPosition: PropTypes.oneOf([
219+
filterPosition: PropTypes.oneOf([
215220
Const.FILTERS_POSITION_TOP,
221+
Const.FILTERS_POSITION_INLINE,
216222
Const.FILTERS_POSITION_BOTTOM
217223
]),
218224
footerClasses: PropTypes.string,
@@ -256,7 +262,8 @@ BootstrapTable.defaultProps = {
256262
cellEdit: {
257263
mode: null,
258264
nonEditableRows: []
259-
}
265+
},
266+
filterPosition: Const.FILTERS_POSITION_INLINE
260267
};
261268

262269
export default BootstrapTable;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export default {
1313
TYPE_NUMBER: 'number',
1414
TYPE_BOOLEAN: 'bool',
1515
TYPE_DATE: 'date',
16+
FILTERS_POSITION_INLINE: 'inline',
1617
FILTERS_POSITION_TOP: 'top',
1718
FILTERS_POSITION_BOTTOM: 'bottom'
1819
};

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const Filters = (props) => {
1010
columns,
1111
onFilter,
1212
currFilters,
13-
position,
13+
filterPosition,
1414
onExternalFilter,
1515
className
1616
} = props;
@@ -35,25 +35,26 @@ const Filters = (props) => {
3535
});
3636

3737
return (
38-
<tfoot
38+
<tbody
3939
className={ className }
4040
style={ {
4141
display:
42-
position === Const.FILTERS_POSITION_TOP
43-
? 'table-header-group'
44-
: 'table-footer-group'
42+
filterPosition === Const.FILTERS_POSITION_TOP
43+
? 'table-header-group'
44+
: 'table-footer-group'
4545
} }
4646
>
4747
<tr>{filterColumns}</tr>
48-
</tfoot>
48+
</tbody>
4949
);
5050
};
5151

5252
Filters.propTypes = {
5353
columns: PropTypes.array.isRequired,
5454
onFilter: PropTypes.func,
55-
position: PropTypes.oneOf([
55+
filterPosition: PropTypes.oneOf([
5656
Const.FILTERS_POSITION_TOP,
57+
Const.FILTERS_POSITION_INLINE,
5758
Const.FILTERS_POSITION_BOTTOM
5859
]),
5960
currFilters: PropTypes.object,

packages/react-bootstrap-table2/src/header-cell.js

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class HeaderCell extends eventDelegater(React.Component) {
2121
isLastSorting,
2222
onFilter,
2323
currFilters,
24+
filterPosition,
2425
onExternalFilter
2526
} = this.props;
2627

@@ -104,18 +105,20 @@ class HeaderCell extends eventDelegater(React.Component) {
104105
if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses);
105106
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
106107

107-
if (filterRenderer) {
108-
const onCustomFilter = onExternalFilter(column, filter.props.type);
109-
filterElm = filterRenderer(onCustomFilter, column);
110-
} else if (filter) {
111-
filterElm = (
112-
<filter.Filter
113-
{ ...filter.props }
114-
filterState={ currFilters[column.dataField] }
115-
onFilter={ onFilter }
116-
column={ column }
117-
/>
118-
);
108+
if (filterPosition === Const.FILTERS_POSITION_INLINE) {
109+
if (filterRenderer) {
110+
const onCustomFilter = onExternalFilter(column, filter.props.type);
111+
filterElm = filterRenderer(onCustomFilter, column);
112+
} else if (filter) {
113+
filterElm = (
114+
<filter.Filter
115+
{ ...filter.props }
116+
filterState={ currFilters[column.dataField] }
117+
onFilter={ onFilter }
118+
column={ column }
119+
/>
120+
);
121+
}
119122
}
120123

121124
const children = headerFormatter ?
@@ -180,6 +183,8 @@ HeaderCell.propTypes = {
180183
sortCaret: PropTypes.func,
181184
isLastSorting: PropTypes.bool,
182185
onFilter: PropTypes.func,
186+
filterPosition: PropTypes.oneOf([Const.FILTERS_POSITION_INLINE,
187+
Const.FILTERS_POSITION_BOTTOM, Const.FILTERS_POSITION_TOP]),
183188
currFilters: PropTypes.object,
184189
onExternalFilter: PropTypes.func
185190
};

0 commit comments

Comments
 (0)