refine remote cell edit

This commit is contained in:
AllenFang 2018-01-04 23:19:13 +08:00
parent fcf7800f96
commit a50a12426a
6 changed files with 58 additions and 64 deletions

View File

@ -1,3 +1,5 @@
/* eslint no-param-reassign: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { filters } from './filter';
@ -15,14 +17,20 @@ export default (Base, {
constructor(props) {
super(props);
this.state = { currFilters: {}, isDataChanged: false };
this.state = { currFilters: {}, isDataChanged: props.isDataChanged || false };
this.onFilter = this.onFilter.bind(this);
}
componentWillReceiveProps(nextProps) {
componentWillReceiveProps({ isDataChanged, store, columns }) {
// consider to use lodash.isEqual
if (JSON.stringify(this.state.currFilters) !== JSON.stringify(nextProps.store.filters)) {
this.setState(() => ({ isDataChanged: true, currFilters: nextProps.store.filters }));
if (JSON.stringify(this.state.currFilters) !== JSON.stringify(store.filters)) {
this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
} else if (isDataChanged) {
if (!(this.isRemoteFiltering() || this.isRemotePagination()) &&
Object.keys(this.state.currFilters).length > 0) {
store.filteredData = filters(store, columns, _)(this.state.currFilters);
}
this.setState(() => ({ isDataChanged }));
} else {
this.setState(() => ({ isDataChanged: false }));
}

View File

@ -130,13 +130,11 @@ BootstrapTable.propTypes = {
filter: PropTypes.object,
cellEdit: PropTypes.shape({
mode: PropTypes.oneOf([Const.CLICK_TO_CELL_EDIT, Const.DBCLICK_TO_CELL_EDIT]).isRequired,
onUpdate: PropTypes.func,
onErrorMessageDisappear: PropTypes.func,
blurToSave: PropTypes.bool,
beforeSaveCell: PropTypes.func,
afterSaveCell: PropTypes.func,
nonEditableRows: PropTypes.func,
editing: PropTypes.bool,
timeToCloseMessage: PropTypes.number,
errorMessage: PropTypes.string
}),
@ -146,8 +144,7 @@ BootstrapTable.propTypes = {
currEditCell: PropTypes.shape({
ridx: PropTypes.number,
cidx: PropTypes.number,
message: PropTypes.string,
editing: PropTypes.bool
message: PropTypes.string
}),
selectRow: PropTypes.shape({
mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired,

View File

@ -1,44 +1,54 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import _ from '../utils';
import remoteResolver from '../props-resolver/remote-resolver';
export default (Base, parentProps) =>
class CellEditWrapper extends Component {
export default Base =>
class CellEditWrapper extends remoteResolver(Component) {
constructor(props) {
super(props);
this.startEditing = this.startEditing.bind(this);
this.escapeEditing = this.escapeEditing.bind(this);
this.completeEditing = this.completeEditing.bind(this);
this.handleCellUpdate = this.handleCellUpdate.bind(this);
this.updateEditingWithErr = this.updateEditingWithErr.bind(this);
this.state = {
ridx: null,
cidx: null,
message: null,
editing: false
isDataChanged: false
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.cellEdit) {
if (nextProps.cellEdit.editing) {
if (nextProps.cellEdit && this.isRemoteCellEdit()) {
if (nextProps.cellEdit.errorMessage) {
this.setState(() => ({
...this.state,
isDataChanged: false,
message: nextProps.cellEdit.errorMessage
}));
} else {
this.setState(() => ({
isDataChanged: true
}));
this.escapeEditing();
}
} else {
this.setState(() => ({
isDataChanged: false
}));
}
}
handleCellUpdate(row, column, newValue) {
const { keyField, cellEdit } = this.props;
const { keyField, cellEdit, store } = this.props;
const { beforeSaveCell, afterSaveCell } = cellEdit;
const oldValue = _.get(row, column.dataField);
const rowId = _.get(row, keyField);
if (_.isFunction(beforeSaveCell)) beforeSaveCell(oldValue, newValue, row, column);
if (parentProps.onUpdateCell(rowId, column.dataField, newValue)) {
if (this.isRemoteCellEdit()) {
this.handleCellChange(rowId, column.dataField, newValue);
} else {
store.edit(rowId, column.dataField, newValue);
if (_.isFunction(afterSaveCell)) afterSaveCell(oldValue, newValue, row, column);
this.completeEditing();
}
@ -49,7 +59,7 @@ export default (Base, parentProps) =>
ridx: null,
cidx: null,
message: null,
editing: false
isDataChanged: true
}));
}
@ -58,7 +68,7 @@ export default (Base, parentProps) =>
this.setState(() => ({
ridx,
cidx,
editing: true
isDataChanged: false
}));
};
@ -69,27 +79,21 @@ export default (Base, parentProps) =>
escapeEditing() {
this.setState(() => ({
ridx: null,
cidx: null,
editing: false
}));
}
updateEditingWithErr(message) {
this.setState(() => ({
...this.state,
message
cidx: null
}));
}
render() {
const { isDataChanged, ...rest } = this.state;
return (
<Base
{ ...this.props }
isDataChanged={ isDataChanged }
data={ this.props.store.data }
onCellUpdate={ this.handleCellUpdate }
onStartEditing={ this.startEditing }
onEscapeEditing={ this.escapeEditing }
currEditCell={ { ...this.state } }
currEditCell={ { ...rest } }
/>
);
}

View File

@ -16,11 +16,10 @@ const withDataStore = Base =>
this.store = new Store(props.keyField);
this.store.data = props.data;
this.wrapComponents();
this.handleUpdateCell = this.handleUpdateCell.bind(this);
}
componentWillReceiveProps(nextProps) {
this.store.data = nextProps.data;
this.store.setAllData(nextProps.data);
}
wrapComponents() {
@ -45,41 +44,13 @@ const withDataStore = Base =>
});
}
if (cellEdit) {
this.BaseComponent = withCellEdit(this.BaseComponent);
}
if (selectRow) {
this.BaseComponent = withSelection(this.BaseComponent);
}
if (cellEdit) {
this.BaseComponent = withCellEdit(this.BaseComponent, {
ref: node => this.cellEditWrapper = node,
onUpdateCell: this.handleUpdateCell
});
}
}
handleUpdateCell(rowId, dataField, newValue) {
const { cellEdit } = this.props;
// handle cell editing internal
if (!cellEdit.onUpdate) {
this.store.edit(rowId, dataField, newValue);
return true;
}
// handle cell editing external
const aPromise = cellEdit.onUpdate(rowId, dataField, newValue);
if (_.isDefined(aPromise) && aPromise !== false) { // TODO: should be a promise here
aPromise.then((result = true) => {
const response = result === true ? {} : result;
if (_.isObject(response)) {
const { value } = response;
this.store.edit(rowId, dataField, value || newValue);
this.cellEditWrapper.completeEditing();
}
}).catch((e) => {
this.cellEditWrapper.updateEditingWithErr(e.message);
});
}
return false;
}
render() {

View File

@ -10,7 +10,7 @@ export default ExtendBase =>
filters: store.filters,
sortField: store.sortField,
sortOrder: store.sortOrder,
data: store.data,
data: store.getAllData(),
...state
};
}
@ -30,6 +30,11 @@ export default ExtendBase =>
return remote === true || (_.isObject(remote) && remote.sort);
}
isRemoteCellEdit() {
const { remote } = this.props;
return remote === true || (_.isObject(remote) && remote.cellEdit);
}
handleRemotePageChange() {
this.props.onTableChange('pagination', this.getNewestState());
}
@ -46,4 +51,9 @@ export default ExtendBase =>
handleSortChange() {
this.props.onTableChange('sort', this.getNewestState());
}
handleCellChange(rowId, dataField, newValue) {
const cellEdit = { rowId, dataField, newValue };
this.props.onTableChange('cellEdit', this.getNewestState({ cellEdit }));
}
};

View File

@ -34,6 +34,10 @@ export default class Store {
return this._data;
}
setAllData(data) {
this._data = data;
}
get data() {
if (Object.keys(this._filters).length > 0) {
return this._filteredData;