Compare commits

...

14 Commits

Author SHA1 Message Date
AllenFang
88234fead0 Publish
- react-bootstrap-table2-editor@0.1.1
 - react-bootstrap-table2-example@0.1.1
 - react-bootstrap-table2-filter@0.1.2
 - react-bootstrap-table2-overlay@0.1.1
 - react-bootstrap-table2-paginator@0.1.1
 - react-bootstrap-table-next@0.1.2
2018-02-01 23:17:40 +08:00
Allen
dea780519f Merge pull request #188 from react-bootstrap-table/develop
2018/02/02 release
2018-02-01 23:07:20 +08:00
AllenFang
38bb2290dc README 2018-01-31 23:50:02 +08:00
AllenFang
8bfbc14bd9 fix #185 2018-01-31 00:01:04 +08:00
Allen
ee4eb8f2c6 Merge pull request #183 from react-bootstrap-table/feat/select-filter
Select filter
2018-01-30 23:53:50 +08:00
AllenFang
8fa6389c81 patch docs 2018-01-30 23:39:18 +08:00
AllenFang
9a354444d0 fix bug for wrap not existing method 2018-01-30 23:25:58 +08:00
AllenFang
2533a63430 patch test for select component 2018-01-30 23:20:47 +08:00
AllenFang
81e0080aa6 add styles for filter modules 2018-01-30 23:20:47 +08:00
AllenFang
094a0682f1 add select filter stories 2018-01-30 23:20:47 +08:00
AllenFang
3f2c6201d9 implement select filter 2018-01-30 23:20:47 +08:00
AllenFang
280c423298 fix #180 2018-01-28 22:09:00 +08:00
AllenFang
fc813e80b6 fix #172 2018-01-28 21:57:30 +08:00
AllenFang
4bb2ae2ba0 fix typo 2018-01-28 21:53:33 +08:00
24 changed files with 838 additions and 20 deletions

View File

@@ -542,6 +542,7 @@ Or take a callback function
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters: Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
* Text(`textFilter`) * Text(`textFilter`)
* Select(`selectFilter`)
We have a quick example to show you how to use `column.filter`: We have a quick example to show you how to use `column.filter`:

View File

@@ -83,7 +83,8 @@ Please see [available filter configuration](https://react-bootstrap-table.github
- [x] Remote Filter - [x] Remote Filter
- [ ] Custom Filter Component - [ ] Custom Filter Component
- [ ] Regex Filter - [ ] Regex Filter
- [ ] Select Filter - [x] Select Filter
- [x] Custom Select Filter
- [ ] Number Filter - [ ] Number Filter
- [ ] Date Filter - [ ] Date Filter
- [ ] Array Filter - [ ] Array Filter

View File

@@ -24,6 +24,7 @@ const JS_SKIPS = `+(${TEST}|${LIB}|${DIST}|${NODE_MODULES})`;
const STYLE_PKGS = [ const STYLE_PKGS = [
'react-bootstrap-table2', 'react-bootstrap-table2',
'react-bootstrap-table2-filter',
'react-bootstrap-table2-paginator' 'react-bootstrap-table2-paginator'
].reduce((pkg, curr) => `${curr}|${pkg}`, ''); ].reduce((pkg, curr) => `${curr}|${pkg}`, '');

View File

@@ -7,6 +7,7 @@ const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filt
const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js'); const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js');
const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style'); const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style');
const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style'); const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style');
const filterStylePath = path.join(__dirname, '../../react-bootstrap-table2-filter/style');
const storyPath = path.join(__dirname, '../stories'); const storyPath = path.join(__dirname, '../stories');
const examplesPath = path.join(__dirname, '../examples'); const examplesPath = path.join(__dirname, '../examples');
const srcPath = path.join(__dirname, '../src'); const srcPath = path.join(__dirname, '../src');
@@ -40,7 +41,7 @@ const loaders = [{
}, { }, {
test: /\.scss$/, test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'], use: ['style-loader', 'css-loader', 'sass-loader'],
include: [storyPath, sourceStylePath, paginationStylePath], include: [storyPath, sourceStylePath, paginationStylePath, filterStylePath],
}, { }, {
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/, test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000', loader: 'url-loader?limit=100000',

View File

@@ -0,0 +1,80 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
withoutEmptyOption: true,
style: {
backgroundColor: 'pink'
},
className: 'test-classname',
datamycustomattr: 'datamycustomattr'
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
withoutEmptyOption: true,
style: {
backgroundColor: 'pink'
},
className: 'test-classname',
datamycustomattr: 'datamycustomattr'
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,70 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
defaultValue: 2
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
defaultValue: 2
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,69 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(6);
const selectOptions = {
'03': '03',
'04': '04',
'01': '01'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: selectFilter({
options: selectOptions,
comparator: Comparator.LIKE // default is Comparator.EQ
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = {
'03': '03',
'04': '04',
'01': '01'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: selectFilter({
options: selectOptions,
comparator: Comparator.LIKE // default is Comparator.EQ
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<h3>Select Filter with LIKE Comparator</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,68 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -20,6 +20,13 @@ export const productsGenerator = (quantity = 5, callback) => {
); );
}; };
export const productsQualityGenerator = (quantity = 5) =>
Array.from({ length: quantity }, (value, index) => ({
id: index,
name: `Item name ${index}`,
quality: index % 3
}));
export const jobsGenerator = (quantity = 5) => export const jobsGenerator = (quantity = 5) =>
Array.from({ length: quantity }, (value, index) => ({ Array.from({ length: quantity }, (value, index) => ({
id: index, id: index,

View File

@@ -39,6 +39,10 @@ import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-defau
import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator'; import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator';
import CustomTextFilter from 'examples/column-filter/custom-text-filter'; import CustomTextFilter from 'examples/column-filter/custom-text-filter';
import CustomFilterValue from 'examples/column-filter/custom-filter-value'; import CustomFilterValue from 'examples/column-filter/custom-filter-value';
import SelectFilter from 'examples/column-filter/select-filter';
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
// work on rows // work on rows
import RowStyleTable from 'examples/rows/row-style'; import RowStyleTable from 'examples/rows/row-style';
@@ -98,6 +102,7 @@ import 'stories/stylesheet/tomorrow.min.css';
import 'stories/stylesheet/storybook.scss'; import 'stories/stylesheet/storybook.scss';
import '../../react-bootstrap-table2/style/react-bootstrap-table2.scss'; import '../../react-bootstrap-table2/style/react-bootstrap-table2.scss';
import '../../react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss'; import '../../react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss';
import '../../react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss';
// import { action } from '@storybook/addon-actions'; // import { action } from '@storybook/addon-actions';
@@ -140,6 +145,10 @@ storiesOf('Column Filter', module)
.add('Text Filter with Comparator', () => <TextFilterComparator />) .add('Text Filter with Comparator', () => <TextFilterComparator />)
.add('Custom Text Filter', () => <CustomTextFilter />) .add('Custom Text Filter', () => <CustomTextFilter />)
// add another filter type example right here. // add another filter type example right here.
.add('Select Filter', () => <SelectFilter />)
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
.add('Custom Select Filter', () => <CustomSelectFilter />)
.add('Custom Filter Value', () => <CustomFilterValue />); .add('Custom Filter Value', () => <CustomFilterValue />);
storiesOf('Work on Rows', module) storiesOf('Work on Rows', module)

View File

@@ -17,8 +17,19 @@ $ npm install react-bootstrap-table2-filter --save
You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters: You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters:
* TextFilter * TextFilter
* SelectFilter
* **Coming soon!** * **Coming soon!**
## Add CSS
```js
// es5
require('react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css');
// es6
import 'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css';
```
## Text Filter ## Text Filter
Following is a quick demo for enable the column filter on **Product Price** column!! Following is a quick demo for enable the column filter on **Product Price** column!!
@@ -53,3 +64,48 @@ const priceFilter = textFilter({
// omit... // omit...
``` ```
## Select Filter
A quick example:
```js
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
// omit...
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [
..., {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
```
Following is an example for custom select filter:
```js
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
// omit...
const qualityFilter = selectFilter({
options: selectOptions,
placeholder: 'My Custom PlaceHolder', // custom the input placeholder
className: 'my-custom-text-filter', // custom classname on input
defaultValue: '2', // default filtering value
comparator: Comparator.LIKE, // default is Comparator.EQ
style: { ... }, // your custom styles on input
withoutEmptyOption: true // hide the default select option
});
// omit...
```

View File

@@ -1,4 +1,5 @@
import TextFilter from './src/components/text'; import TextFilter from './src/components/text';
import SelectFilter from './src/components/select';
import wrapperFactory from './src/wrapper'; import wrapperFactory from './src/wrapper';
import * as Comparison from './src/comparison'; import * as Comparison from './src/comparison';
@@ -13,3 +14,8 @@ export const textFilter = (props = {}) => ({
Filter: TextFilter, Filter: TextFilter,
props props
}); });
export const selectFilter = (props = {}) => ({
Filter: SelectFilter,
props
});

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-filter", "name": "react-bootstrap-table2-filter",
"version": "0.1.1", "version": "0.1.2",
"description": "it's a column filter addon for react-bootstrap-table2", "description": "it's a column filter addon for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -0,0 +1,132 @@
/* eslint react/require-default-props: 0 */
/* eslint no-return-assign: 0 */
/* eslint react/no-unused-prop-types: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { LIKE, EQ } from '../comparison';
import { FILTER_TYPE } from '../const';
function optionsEquals(currOpts, prevOpts) {
const keys = Object.keys(currOpts);
for (let i = 0; i < keys.length; i += 1) {
if (currOpts[keys[i]] !== prevOpts[keys[i]]) {
return false;
}
}
return Object.keys(currOpts).length === Object.keys(prevOpts).length;
}
class SelectFilter extends Component {
constructor(props) {
super(props);
this.filter = this.filter.bind(this);
const isSelected = props.options[props.defaultValue] !== undefined;
this.state = { isSelected };
}
componentDidMount() {
const value = this.selectInput.value;
if (value && value !== '') {
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
}
componentDidUpdate(prevProps) {
let needFilter = false;
if (this.props.defaultValue !== prevProps.defaultValue) {
needFilter = true;
} else if (!optionsEquals(this.props.options, prevProps.options)) {
needFilter = true;
}
if (needFilter) {
const value = this.selectInput.value;
if (value) {
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
}
}
getOptions() {
const optionTags = [];
const { options, placeholder, column, withoutEmptyOption } = this.props;
if (!withoutEmptyOption) {
optionTags.push((
<option key="-1" value="">{ placeholder || `Select ${column.text}...` }</option>
));
}
Object.keys(options).forEach(key =>
optionTags.push(<option key={ key } value={ key }>{ options[key] }</option>)
);
return optionTags;
}
cleanFiltered() {
const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : '';
this.setState(() => ({ isSelected: value !== '' }));
this.selectInput.value = value;
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
applyFilter(value) {
this.selectInput.value = value;
this.setState(() => ({ isSelected: value !== '' }));
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
filter(e) {
const { value } = e.target;
this.setState(() => ({ isSelected: value !== '' }));
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
render() {
const {
style,
className,
defaultValue,
onFilter,
column,
options,
comparator,
withoutEmptyOption,
...rest
} = this.props;
const selectClass =
`filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`;
return (
<select
{ ...rest }
ref={ n => this.selectInput = n }
style={ style }
className={ selectClass }
onChange={ this.filter }
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
>
{ this.getOptions() }
</select>
);
}
}
SelectFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
options: PropTypes.object.isRequired,
comparator: PropTypes.oneOf([LIKE, EQ]),
placeholder: PropTypes.string,
style: PropTypes.object,
className: PropTypes.string,
withoutEmptyOption: PropTypes.bool,
defaultValue: PropTypes.any
};
SelectFilter.defaultProps = {
defaultValue: '',
className: '',
withoutEmptyOption: false,
comparator: EQ
};
export default SelectFilter;

View File

@@ -1,5 +1,6 @@
export const FILTER_TYPE = { export const FILTER_TYPE = {
TEXT: 'TEXT' TEXT: 'TEXT',
SELECT: 'SELECT'
}; };
export const FILTER_DELAY = 500; export const FILTER_DELAY = 500;

View File

@@ -3,7 +3,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { filters } from './filter'; import { filters } from './filter';
import { LIKE } from './comparison'; import { LIKE, EQ } from './comparison';
import { FILTER_TYPE } from './const';
export default (Base, { export default (Base, {
_, _,
@@ -47,7 +48,8 @@ export default (Base, {
if (!_.isDefined(filterVal) || filterVal === '') { if (!_.isDefined(filterVal) || filterVal === '') {
delete currFilters[dataField]; delete currFilters[dataField];
} else { } else {
const { comparator = LIKE } = filter.props; // select default comparator is EQ, others are LIKE
const { comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE) } = filter.props;
currFilters[dataField] = { filterVal, filterType, comparator }; currFilters[dataField] = { filterVal, filterType, comparator };
} }
store.filters = currFilters; store.filters = currFilters;

View File

@@ -0,0 +1,14 @@
.react-bootstrap-table > table > thead > tr > th .filter {
font-weight: normal;
}
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected {
color: lightgrey;
font-style: italic;
}
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) {
color: initial;
font-style: initial;
}

View File

@@ -0,0 +1,296 @@
import 'jsdom-global/register';
import React from 'react';
import sinon from 'sinon';
import { mount } from 'enzyme';
import SelectFilter from '../../src/components/select';
import { FILTER_TYPE } from '../../src/const';
describe('Select Filter', () => {
let wrapper;
let instance;
const onFilter = sinon.stub();
const column = {
dataField: 'quality',
text: 'Product Quality'
};
const options = {
0: 'Bad',
1: 'Good',
2: 'Unknow'
};
afterEach(() => {
onFilter.reset();
});
describe('initialization', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
);
instance = wrapper.instance();
});
it('should have correct state', () => {
expect(instance.state.isSelected).toBeFalsy();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select')).toHaveLength(1);
expect(wrapper.find('.select-filter')).toHaveLength(1);
expect(wrapper.find('.placeholder-selected')).toHaveLength(1);
});
it('should rendering select options correctly', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(Object.keys(options).length + 1);
expect(select.childAt(0).text()).toEqual(`Select ${column.text}...`);
Object.keys(options).forEach((key, i) => {
expect(select.childAt(i + 1).prop('value')).toEqual(key);
expect(select.childAt(i + 1).text()).toEqual(options[key]);
});
});
});
describe('when defaultValue is defined', () => {
let defaultValue;
describe('and it is valid', () => {
beforeEach(() => {
defaultValue = '0';
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
defaultValue={ defaultValue }
/>
);
instance = wrapper.instance();
});
it('should have correct state', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.placeholder-selected')).toHaveLength(0);
});
it('should calling onFilter on componentDidMount', () => {
expect(onFilter.calledOnce).toBeTruthy();
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
});
describe('when placeholder is defined', () => {
const placeholder = 'test';
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
placeholder={ placeholder }
/>
);
instance = wrapper.instance();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
const select = wrapper.find('select');
expect(select.childAt(0).text()).toEqual(placeholder);
});
});
describe('when style is defined', () => {
const style = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
style={ style }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select').prop('style')).toEqual(style);
});
});
describe('when withoutEmptyOption is defined', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
withoutEmptyOption
/>
);
});
it('should rendering select without default empty option', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(Object.keys(options).length);
});
});
describe('componentDidUpdate', () => {
let prevProps;
describe('when props.defaultValue is diff from prevProps.defaultValue', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
defaultValue="0"
/>
);
prevProps = {
column,
options,
defaultValue: '1'
};
instance = wrapper.instance();
instance.componentDidUpdate(prevProps);
});
it('should update', () => {
expect(onFilter.callCount).toBe(2);
expect(onFilter.calledWith(
column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
describe('when props.options is diff from prevProps.options', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ {
...options,
3: 'Best'
} }
defaultValue="1"
/>
);
prevProps = {
column,
options
};
instance = wrapper.instance();
instance.componentDidUpdate(prevProps);
});
it('should update', () => {
expect(onFilter.callCount).toBe(2);
expect(onFilter.calledWith(
column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
});
describe('cleanFiltered', () => {
describe('when props.defaultValue is defined', () => {
const defaultValue = '0';
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
defaultValue={ defaultValue }
/>
);
instance = wrapper.instance();
instance.cleanFiltered();
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(2);
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
describe('when props.defaultValue is not defined', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
/>
);
instance = wrapper.instance();
instance.cleanFiltered();
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeFalsy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(1);
});
});
});
describe('applyFilter', () => {
const value = '2';
beforeEach(() => {
wrapper = mount(
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
);
instance = wrapper.instance();
instance.applyFilter(value);
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(1);
expect(onFilter.calledWith(column, value, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
describe('filter', () => {
const event = { target: { value: 'tester' } };
beforeEach(() => {
wrapper = mount(
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
);
instance = wrapper.instance();
instance.filter(event);
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(1);
expect(onFilter.calledWith(column, event.target.value, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
});

View File

@@ -1,6 +1,6 @@
# react-bootstrap-table2-pagination # react-bootstrap-table2-paginator
`react-bootstrap-table2` separate the pagination code base to [`react-bootstrap-table2-pagination`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-paginator), so there's a little bit different when you use pagination. In the following, we are going to show you how to enable and configure the a pagination table `react-bootstrap-table2` separate the pagination code base to [`react-bootstrap-table2-paginator`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-paginator), so there's a little bit different when you use pagination. In the following, we are going to show you how to enable and configure the a pagination table
**[Live Demo For Pagination](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination)** **[Live Demo For Pagination](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination)**
@@ -11,7 +11,7 @@
## Install ## Install
```sh ```sh
$ npm install react-bootstrap-table2-pagination --save $ npm install react-bootstrap-table2-paginator --save
``` ```
## Add CSS ## Add CSS

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table-next", "name": "react-bootstrap-table-next",
"version": "0.1.1", "version": "0.1.2",
"description": "Next generation of react-bootstrap-table", "description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
export default ExtendBase => export default ExtendBase =>
class ColumnResolver extends ExtendBase { class ColumnResolver extends ExtendBase {
visibleColumnSize() { visibleColumnSize() {
return this.props.columns.length; return this.props.columns.filter(c => !c.hidden).length;
} }
}; };

View File

@@ -13,12 +13,13 @@ export default class SelectionCell extends Component {
selected: PropTypes.bool, selected: PropTypes.bool,
onRowSelect: PropTypes.func, onRowSelect: PropTypes.func,
disabled: PropTypes.bool, disabled: PropTypes.bool,
rowIndex: PropTypes.number rowIndex: PropTypes.number,
clickToSelect: PropTypes.bool
} }
constructor() { constructor() {
super(); super();
this.handleRowClick = this.handleRowClick.bind(this); this.handleClick = this.handleClick.bind(this);
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
@@ -27,17 +28,19 @@ export default class SelectionCell extends Component {
return nextProps.selected !== selected; return nextProps.selected !== selected;
} }
handleRowClick() { handleClick() {
const { const {
mode: inputType, mode: inputType,
rowKey, rowKey,
selected, selected,
onRowSelect, onRowSelect,
disabled, disabled,
rowIndex rowIndex,
clickToSelect
} = this.props; } = this.props;
if (disabled) return; if (disabled) return;
if (clickToSelect) return;
const checked = inputType === Const.ROW_SELECT_SINGLE const checked = inputType === Const.ROW_SELECT_SINGLE
? true ? true
@@ -54,7 +57,7 @@ export default class SelectionCell extends Component {
} = this.props; } = this.props;
return ( return (
<td onClick={ this.handleRowClick }> <td onClick={ this.handleClick }>
<input <input
type={ inputType } type={ inputType }
checked={ selected } checked={ selected }

View File

@@ -1,4 +1,5 @@
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
/* eslint react/no-array-index-key: 0 */
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@@ -126,7 +127,7 @@ class Row extends Component {
} }
return ( return (
<EditingCell <EditingCell
key={ content } key={ `${content}-${index}` }
row={ row } row={ row }
column={ column } column={ column }
className={ editCellclasses } className={ editCellclasses }
@@ -137,7 +138,7 @@ class Row extends Component {
} }
return ( return (
<Cell <Cell
key={ content } key={ `${content}-${index}` }
row={ row } row={ row }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columnIndex={ index } columnIndex={ index }

View File

@@ -34,12 +34,12 @@ describe('<SelectionCell />', () => {
}); });
}); });
describe('handleRowClick', () => { describe('handleClick', () => {
describe('when <input /> was been clicked', () => { describe('when <input /> was been clicked', () => {
const rowKey = 1; const rowKey = 1;
const selected = true; const selected = true;
let mockOnRowSelect; let mockOnRowSelect;
const spy = sinon.spy(SelectionCell.prototype, 'handleRowClick'); const spy = sinon.spy(SelectionCell.prototype, 'handleClick');
beforeEach(() => { beforeEach(() => {
mockOnRowSelect = sinon.stub(); mockOnRowSelect = sinon.stub();