mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
implement remote sorting
This commit is contained in:
parent
bdfc4ebcad
commit
01337f50a7
@ -249,13 +249,17 @@ There's only two arguments will be passed to `onTableChange`: `type` and `newSta
|
||||
|
||||
* `filter`
|
||||
* `pagination`
|
||||
* `sort`
|
||||
|
||||
Following is a shape of `newState`
|
||||
|
||||
```js
|
||||
{
|
||||
page, // newest page
|
||||
sizePerPage, //newest sizePerPage
|
||||
filters // an object which have current filter status per column
|
||||
sizePerPage, // newest sizePerPage
|
||||
sortField, // newest sort field
|
||||
sortOrder, // newest sort order
|
||||
filters, // an object which have current filter status per column
|
||||
data // when you enable remote sort, you may need to base on data to sort if data is filtered/searched
|
||||
}
|
||||
```
|
||||
106
packages/react-bootstrap-table2-example/examples/remote/remote-sort.js
vendored
Normal file
106
packages/react-bootstrap-table2-example/examples/remote/remote-sort.js
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/* eslint no-restricted-syntax: 0 */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import BootstrapTable from 'react-bootstrap-table2';
|
||||
import Code from 'components/common/code-block';
|
||||
import { productsGenerator } from 'utils/common';
|
||||
|
||||
const products = productsGenerator(5);
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
sort: true
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
sort: true
|
||||
}];
|
||||
|
||||
const sourceCode = `\
|
||||
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID',
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
filter: textFilter()
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
filter: textFilter()
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
`;
|
||||
|
||||
const RemoteSort = props => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
remote={ { sort: true } }
|
||||
keyField="id"
|
||||
data={ props.data }
|
||||
columns={ columns }
|
||||
onTableChange={ props.onTableChange }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
|
||||
RemoteSort.propTypes = {
|
||||
data: PropTypes.array.isRequired,
|
||||
onTableChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
class Container extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: products
|
||||
};
|
||||
}
|
||||
|
||||
handleTableChange = (type, { sortField, sortOrder, data }) => {
|
||||
setTimeout(() => {
|
||||
let result;
|
||||
if (sortOrder === 'asc') {
|
||||
result = data.sort((a, b) => {
|
||||
if (a[sortField] > b[sortField]) {
|
||||
return 1;
|
||||
} else if (b[sortField] > a[sortField]) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
result = data.sort((a, b) => {
|
||||
if (a[sortField] > b[sortField]) {
|
||||
return -1;
|
||||
} else if (b[sortField] > a[sortField]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
this.setState(() => ({
|
||||
data: result
|
||||
}));
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RemoteSort
|
||||
data={ this.state.data }
|
||||
onTableChange={ this.handleTableChange }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Container;
|
||||
@ -88,6 +88,7 @@ import EmptyTableOverlay from 'examples/loading-overlay/empty-table-overlay';
|
||||
import TableOverlay from 'examples/loading-overlay/table-overlay';
|
||||
|
||||
// remote
|
||||
import RemoteSort from 'examples/remote/remote-sort';
|
||||
import RemoteFilter from 'examples/remote/remote-filter';
|
||||
import RemotePaginationTable from 'examples/remote/remote-pagination';
|
||||
import RemoteAll from 'examples/remote/remote-all';
|
||||
@ -190,6 +191,7 @@ storiesOf('EmptyTableOverlay', module)
|
||||
.add('Table Overlay', () => <TableOverlay />);
|
||||
|
||||
storiesOf('Remote', module)
|
||||
.add('Remote Sort', () => <RemoteSort />)
|
||||
.add('Remote Filter', () => <RemoteFilter />)
|
||||
.add('Remote Pagination', () => <RemotePaginationTable />)
|
||||
.add('Remote All', () => <RemoteAll />);
|
||||
|
||||
@ -8,6 +8,9 @@ export default ExtendBase =>
|
||||
page: store.page,
|
||||
sizePerPage: store.sizePerPage,
|
||||
filters: store.filters,
|
||||
sortField: store.sortField,
|
||||
sortOrder: store.sortOrder,
|
||||
data: store.data,
|
||||
...state
|
||||
};
|
||||
}
|
||||
@ -22,6 +25,11 @@ export default ExtendBase =>
|
||||
return remote === true || (_.isObject(remote) && remote.filter);
|
||||
}
|
||||
|
||||
isRemoteSort() {
|
||||
const { remote } = this.props;
|
||||
return remote === true || (_.isObject(remote) && remote.sort);
|
||||
}
|
||||
|
||||
handleRemotePageChange() {
|
||||
this.props.onTableChange('pagination', this.getNewestState());
|
||||
}
|
||||
@ -34,4 +42,8 @@ export default ExtendBase =>
|
||||
}
|
||||
this.props.onTableChange('filter', this.getNewestState(newState));
|
||||
}
|
||||
|
||||
handleSortChange() {
|
||||
this.props.onTableChange('sort', this.getNewestState());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
/* eslint react/prop-types: 0 */
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import remoteResolver from '../props-resolver/remote-resolver';
|
||||
|
||||
export default Base =>
|
||||
class SortWrapper extends Component {
|
||||
class SortWrapper extends remoteResolver(Component) {
|
||||
static propTypes = {
|
||||
store: PropTypes.object.isRequired
|
||||
}
|
||||
@ -22,7 +23,13 @@ export default Base =>
|
||||
const order = defaultSorted[0].order;
|
||||
const column = columns.filter(col => col.dataField === dataField);
|
||||
if (column.length > 0) {
|
||||
store.sortBy(column[0], order);
|
||||
store.setSort(column[0], order);
|
||||
|
||||
if (this.isRemoteSort() || this.isRemotePagination()) {
|
||||
this.handleSortChange();
|
||||
} else {
|
||||
store.sortBy(column[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,15 +39,21 @@ export default Base =>
|
||||
const sortedColumn = nextProps.columns.find(
|
||||
column => column.dataField === nextProps.store.sortField);
|
||||
if (sortedColumn) {
|
||||
nextProps.store.sortBy(sortedColumn, nextProps.store.sortOrder);
|
||||
nextProps.store.sortBy(sortedColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleSort(column) {
|
||||
const { store } = this.props;
|
||||
store.sortBy(column);
|
||||
this.forceUpdate();
|
||||
store.setSort(column);
|
||||
|
||||
if (this.isRemoteSort() || this.isRemotePagination()) {
|
||||
this.handleSortChange();
|
||||
} else {
|
||||
store.sortBy(column);
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@ -21,9 +21,12 @@ export default class Store {
|
||||
if (row) _.set(row, dataField, newValue);
|
||||
}
|
||||
|
||||
sortBy({ dataField, sortFunc }, order) {
|
||||
setSort({ dataField }, order) {
|
||||
this.sortOrder = nextOrder(this)(dataField, order);
|
||||
this.sortField = dataField;
|
||||
}
|
||||
|
||||
sortBy({ sortFunc }) {
|
||||
this.data = sort(this)(sortFunc);
|
||||
}
|
||||
|
||||
|
||||
@ -102,6 +102,52 @@ describe('remoteResolver', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isRemoteSort', () => {
|
||||
describe('when remote is false', () => {
|
||||
beforeEach(() => {
|
||||
shallowContainer();
|
||||
});
|
||||
|
||||
it('should return false', () => {
|
||||
expect(wrapper.instance().isRemoteSort()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when remote is true', () => {
|
||||
beforeEach(() => {
|
||||
shallowContainer({ remote: true });
|
||||
});
|
||||
|
||||
it('should return true', () => {
|
||||
expect(wrapper.instance().isRemoteSort()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when remote.sort is true', () => {
|
||||
beforeEach(() => {
|
||||
shallowContainer({ remote: { sort: true } });
|
||||
});
|
||||
|
||||
it('should return true', () => {
|
||||
expect(wrapper.instance().isRemoteSort()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleSortChange', () => {
|
||||
const onTableChangeCB = sinon.stub();
|
||||
beforeEach(() => {
|
||||
onTableChangeCB.reset();
|
||||
shallowContainer({ onTableChange: onTableChangeCB });
|
||||
wrapper.instance().handleSortChange();
|
||||
});
|
||||
|
||||
it('should calling props.onTableChange correctly', () => {
|
||||
expect(onTableChangeCB.calledOnce).toBeTruthy();
|
||||
expect(onTableChangeCB.calledWith('sort', wrapper.instance().getNewestState())).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleRemotePageChange', () => {
|
||||
const onTableChangeCB = sinon.stub();
|
||||
beforeEach(() => {
|
||||
|
||||
@ -57,28 +57,78 @@ describe('SortWrapper', () => {
|
||||
});
|
||||
|
||||
describe('call handleSort function', () => {
|
||||
let sortBySpy;
|
||||
const sortColumn = columns[0];
|
||||
|
||||
beforeEach(() => {
|
||||
store = new Store(keyField);
|
||||
store.data = data;
|
||||
wrapper = shallow(
|
||||
<SortWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
wrapper.instance().handleSort(sortColumn);
|
||||
sortBySpy = sinon.spy(store, 'sortBy');
|
||||
});
|
||||
|
||||
it('should operating on store correctly', () => {
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
expect(store.sortField).toEqual(sortColumn.dataField);
|
||||
describe('when remote.sort is false', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<SortWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
|
||||
wrapper.instance().handleSort(sortColumn); // sort same column again
|
||||
expect(store.sortOrder).toEqual(Const.SORT_ASC);
|
||||
expect(store.sortField).toEqual(sortColumn.dataField);
|
||||
wrapper.instance().handleSort(sortColumn);
|
||||
});
|
||||
|
||||
it('should operating on store correctly', () => {
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
expect(store.sortField).toEqual(sortColumn.dataField);
|
||||
|
||||
wrapper.instance().handleSort(sortColumn); // sort same column again
|
||||
expect(store.sortOrder).toEqual(Const.SORT_ASC);
|
||||
expect(store.sortField).toEqual(sortColumn.dataField);
|
||||
});
|
||||
|
||||
it('should calling store.sortBy correctly', () => {
|
||||
expect(sortBySpy.calledOnce).toBeTruthy();
|
||||
expect(sortBySpy.calledWith(sortColumn)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when remote.sort is true', () => {
|
||||
let onTableChangeCB;
|
||||
|
||||
beforeEach(() => {
|
||||
onTableChangeCB = sinon.stub();
|
||||
wrapper = shallow(
|
||||
<SortWrapper
|
||||
remote
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
store={ store }
|
||||
onTableChange={ onTableChangeCB }
|
||||
/>
|
||||
);
|
||||
wrapper.instance().handleSort(sortColumn);
|
||||
});
|
||||
|
||||
it('should operating on store correctly', () => {
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
expect(store.sortField).toEqual(sortColumn.dataField);
|
||||
|
||||
wrapper.instance().handleSort(sortColumn); // sort same column again
|
||||
expect(store.sortOrder).toEqual(Const.SORT_ASC);
|
||||
expect(store.sortField).toEqual(sortColumn.dataField);
|
||||
});
|
||||
|
||||
it('should not calling store.sortBy', () => {
|
||||
expect(sortBySpy.calledOnce).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should calling props.onTableChange', () => {
|
||||
expect(onTableChangeCB.calledOnce).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ describe('Store Base', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortBy', () => {
|
||||
describe('setSort', () => {
|
||||
let dataField;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -32,30 +32,43 @@ describe('Store Base', () => {
|
||||
});
|
||||
|
||||
it('should change sortField by dataField param', () => {
|
||||
store.sortBy({ dataField });
|
||||
store.setSort({ dataField });
|
||||
expect(store.sortField).toEqual(dataField);
|
||||
});
|
||||
|
||||
it('should change sortOrder correctly when sortBy same dataField', () => {
|
||||
store.sortBy({ dataField });
|
||||
store.setSort({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
store.sortBy({ dataField });
|
||||
store.setSort({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_ASC);
|
||||
});
|
||||
|
||||
it('should change sortOrder correctly when sortBy different dataField', () => {
|
||||
store.sortBy({ dataField });
|
||||
store.setSort({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
|
||||
dataField = 'id';
|
||||
store.sortBy({ dataField });
|
||||
store.setSort({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
|
||||
dataField = 'name';
|
||||
store.sortBy({ dataField });
|
||||
store.setSort({ dataField });
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
});
|
||||
|
||||
it('should force assign sortOrder correctly if second argument is passed', () => {
|
||||
store.setSort({ dataField }, Const.SORT_DESC);
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortBy', () => {
|
||||
let dataField;
|
||||
|
||||
beforeEach(() => {
|
||||
dataField = 'name';
|
||||
});
|
||||
|
||||
it('should have correct result after sortBy', () => {
|
||||
store.sortBy({ dataField });
|
||||
const result = store.data.map(e => e[dataField]).sort((a, b) => b - a);
|
||||
@ -63,11 +76,6 @@ describe('Store Base', () => {
|
||||
expect(e[dataField]).toEqual(result[i]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should force assign sortOrder correctly if second argument is passed', () => {
|
||||
store.sortBy({ dataField }, Const.SORT_DESC);
|
||||
expect(store.sortOrder).toEqual(Const.SORT_DESC);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit', () => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user