implement selection context

This commit is contained in:
AllenFang
2018-05-13 16:13:59 +08:00
parent 906180ad3f
commit 6d08a24a8f
5 changed files with 106 additions and 123 deletions

View File

@@ -42,7 +42,6 @@ class BootstrapTable extends PropsBaseResolver(Component) {
renderTable() {
const {
store,
columns,
keyField,
id,
@@ -74,8 +73,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
const headerCellSelectionInfo = this.resolveSelectRowPropsForHeader({
onAllRowsSelect: this.props.onAllRowsSelect,
selected: store.selected,
allRowsSelected: isSelectedAll(store)
selected: this.props.selected,
allRowsSelected: isSelectedAll(this.state.data, this.props.selected)
});
const tableCaption = (caption && <Caption>{ caption }</Caption>);
@@ -87,8 +86,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
<Header
columns={ columns }
className={ this.props.headerClasses }
sortField={ store.sortField }
sortOrder={ store.sortOrder }
sortField={ this.props.sortField }
sortOrder={ this.props.sortOrder }
onSort={ this.props.onSort }
onFilter={ this.props.onFilter }
onExternalFilter={ this.props.onExternalFilter }
@@ -103,7 +102,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
noDataIndication={ noDataIndication }
cellEdit={ this.props.cellEdit || {} }
selectRow={ cellSelectionInfo }
selectedRowKeys={ store.selected }
selectedRowKeys={ this.props.selected }
rowStyle={ rowStyle }
rowClasses={ rowClasses }
rowEvents={ rowEvents }
@@ -121,7 +120,6 @@ BootstrapTable.propTypes = {
remote: PropTypes.oneOfType([PropTypes.bool, PropTypes.shape({
pagination: PropTypes.bool
})]),
store: PropTypes.object,
noDataIndication: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
striped: PropTypes.bool,
bordered: PropTypes.bool,

View File

@@ -0,0 +1,94 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import Const from '../const';
import { getRowByRowId } from '../store/rows';
// Consider make selectionHandler become a part of Provider
import * as selectionHandler from '../store/selection';
export default () => {
const SelectionContext = React.createContext();
class SelectionProvider extends React.Component {
static propTypes = {
children: PropTypes.node.isRequired,
data: PropTypes.array.isRequired,
keyField: PropTypes.string.isRequired
}
state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] };
componentWillReceiveProps(nextProps) {
if (nextProps.selectRow) {
this.setState(() => ({
selected: nextProps.selectRow.selected || this.state.selected
}));
}
}
handleRowSelect = (rowKey, checked, rowIndex, e) => {
const { data, keyField, selectRow: { mode, onSelect } } = this.props;
const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...this.state.selected];
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
} else if (checked) { // when select mode is checkbox
currSelected.push(rowKey);
} else {
currSelected = currSelected.filter(value => value !== rowKey);
}
if (onSelect) {
const row = getRowByRowId(data, keyField, rowKey);
onSelect(row, checked, rowIndex, e);
}
this.setState(() => ({ selected: currSelected }));
}
handleAllRowsSelect = (e) => {
const {
data,
keyField,
selectRow: {
onSelectAll,
nonSelectable
}
} = this.props;
const { selected } = this.state;
const anySelected = selectionHandler.isAnySelectedRow(selected, nonSelectable);
const result = !anySelected;
const currSelected = result ?
selectionHandler.selectableKeys(data, keyField, nonSelectable) :
selectionHandler.unSelectableKeys(selected, nonSelectable);
if (onSelectAll) {
onSelectAll(result, selectionHandler.getSelectedRows(data, keyField, currSelected), e);
}
this.setState(() => ({ selected: currSelected }));
}
render() {
return (
<SelectionContext.Provider
value={ {
selected: this.state.selected,
onRowSelect: this.handleRowSelect,
onAllRowsSelect: this.handleAllRowsSelect
} }
>
{ this.props.children }
</SelectionContext.Provider>
);
}
}
return {
Provider: SelectionProvider,
Consumer: SelectionContext.Consumer
};
};

View File

@@ -1,107 +0,0 @@
/* eslint no-param-reassign: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Const from '../const';
import {
isAnySelectedRow,
selectableKeys,
unSelectableKeys,
getSelectedRows
} from '../store/selection';
import { getRowByRowId } from '../store/rows';
export default Base =>
class RowSelectionWrapper extends Component {
static propTypes = {
store: PropTypes.object.isRequired,
selectRow: PropTypes.object.isRequired
}
constructor(props) {
super(props);
this.handleRowSelect = this.handleRowSelect.bind(this);
this.handleAllRowsSelect = this.handleAllRowsSelect.bind(this);
props.store.selected = props.selectRow.selected || [];
this.state = {
selectedRowKeys: props.store.selected
};
}
componentWillReceiveProps(nextProps) {
nextProps.store.selected = nextProps.selectRow.selected || [];
this.setState(() => ({
selectedRowKeys: nextProps.store.selected
}));
}
/**
* row selection handler
* @param {String} rowKey - row key of what was selected.
* @param {Boolean} checked - next checked status of input button.
*/
handleRowSelect(rowKey, checked, rowIndex, e) {
const { selectRow: { mode, onSelect }, store } = this.props;
const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...store.selected];
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
} else if (checked) { // when select mode is checkbox
currSelected.push(rowKey);
} else {
currSelected = currSelected.filter(value => value !== rowKey);
}
store.selected = currSelected;
if (onSelect) {
const row = getRowByRowId(store)(rowKey);
onSelect(row, checked, rowIndex, e);
}
this.setState(() => ({
selectedRowKeys: currSelected
}));
}
/**
* handle all rows selection on header cell by store.selected
*/
handleAllRowsSelect(e) {
const { store, selectRow: {
onSelectAll,
nonSelectable
} } = this.props;
const selected = isAnySelectedRow(store)(nonSelectable);
const result = !selected;
const currSelected = result ?
selectableKeys(store)(nonSelectable) :
unSelectableKeys(store)(nonSelectable);
store.selected = currSelected;
if (onSelectAll) {
onSelectAll(result, getSelectedRows(store), e);
}
this.setState(() => ({
selectedRowKeys: currSelected
}));
}
render() {
return (
<Base
{ ...this.props }
onRowSelect={ this.handleRowSelect }
onAllRowsSelect={ this.handleAllRowsSelect }
/>
);
}
};

View File

@@ -1,4 +1,4 @@
export const matchRow = (keyField, id) => row => row[keyField] === id;
export const getRowByRowId = ({ data, keyField }) => id => data.find(matchRow(keyField, id));
export const getRowByRowId = (data, keyField, id) => data.find(matchRow(keyField, id));

View File

@@ -1,16 +1,16 @@
import _ from '../utils';
import { getRowByRowId } from './rows';
export const isSelectedAll = ({ data, selected }) => data.length === selected.length;
export const isSelectedAll = (data, selected) => data.length === selected.length;
export const isAnySelectedRow = ({ selected }) => (skips = []) => {
export const isAnySelectedRow = (selected, skips = []) => {
if (skips.length === 0) {
return selected.length > 0;
}
return selected.filter(x => !skips.includes(x)).length;
};
export const selectableKeys = ({ data, keyField }) => (skips = []) => {
export const selectableKeys = (data, keyField, skips = []) => {
if (skips.length === 0) {
return data.map(row => _.get(row, keyField));
}
@@ -19,15 +19,13 @@ export const selectableKeys = ({ data, keyField }) => (skips = []) => {
.map(row => _.get(row, keyField));
};
export const unSelectableKeys = ({ selected }) => (skips = []) => {
export const unSelectableKeys = (selected, skips = []) => {
if (skips.length === 0) {
return [];
}
return selected.filter(x => skips.includes(x));
};
export const getSelectedRows = (store) => {
const getRow = getRowByRowId(store);
return store.selected.map(k => getRow(k));
};
export const getSelectedRows = (data, keyField, selected) =>
selected.map(k => getRowByRowId(data, keyField, k));