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 React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { filters } from './filter'; import { filters } from './filter';
@ -15,14 +17,20 @@ export default (Base, {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { currFilters: {}, isDataChanged: false }; this.state = { currFilters: {}, isDataChanged: props.isDataChanged || false };
this.onFilter = this.onFilter.bind(this); this.onFilter = this.onFilter.bind(this);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps({ isDataChanged, store, columns }) {
// consider to use lodash.isEqual // consider to use lodash.isEqual
if (JSON.stringify(this.state.currFilters) !== JSON.stringify(nextProps.store.filters)) { if (JSON.stringify(this.state.currFilters) !== JSON.stringify(store.filters)) {
this.setState(() => ({ isDataChanged: true, currFilters: nextProps.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 { } else {
this.setState(() => ({ isDataChanged: false })); this.setState(() => ({ isDataChanged: false }));
} }

View File

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

View File

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

View File

@ -10,7 +10,7 @@ export default ExtendBase =>
filters: store.filters, filters: store.filters,
sortField: store.sortField, sortField: store.sortField,
sortOrder: store.sortOrder, sortOrder: store.sortOrder,
data: store.data, data: store.getAllData(),
...state ...state
}; };
} }
@ -30,6 +30,11 @@ export default ExtendBase =>
return remote === true || (_.isObject(remote) && remote.sort); return remote === true || (_.isObject(remote) && remote.sort);
} }
isRemoteCellEdit() {
const { remote } = this.props;
return remote === true || (_.isObject(remote) && remote.cellEdit);
}
handleRemotePageChange() { handleRemotePageChange() {
this.props.onTableChange('pagination', this.getNewestState()); this.props.onTableChange('pagination', this.getNewestState());
} }
@ -46,4 +51,9 @@ export default ExtendBase =>
handleSortChange() { handleSortChange() {
this.props.onTableChange('sort', this.getNewestState()); 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; return this._data;
} }
setAllData(data) {
this._data = data;
}
get data() { get data() {
if (Object.keys(this._filters).length > 0) { if (Object.keys(this._filters).length > 0) {
return this._filteredData; return this._filteredData;