3

I'm jumping in on a pretty big React JS project which is using react-data-grid to display a bunch of editable data. Right now, you have to click an Update button to send changes to the server. My task at hand is to create auto-save functionality like so:

  1. User selects cell to edit text
  2. User changes text
  3. User either moves to another cell or clicks away from data-grid
  4. Changes are persisted to the server

Here's what I've tried:

  1. onBlur event on each column. The event will fire, but it seems like the event was attached to a div and not the underlying input control. Therefore, I don't have access to the cell's values at the time this event is fired.
  2. onCellDeselected on the <ReactDataGrid> component itself. It seems like this method is fired immediately upon render, and it only gets fired subsequent times when moving to another cell. If I'm editing the last cell and click away from the data-grid, this callback isn't fired.

Using react-data-grid, how can I effectively gain access to an editable cell's content when the user finishes editing?

djibouti33
  • 12,102
  • 9
  • 83
  • 116

2 Answers2

3

The commits on react-data-grid are handled by the EditorContainer. The commit logic is simple. An editor commits a value when:

  • The editor unmounts
  • Enter is pressed
  • Tab is pressed
  • In some cases when the arrows are pressed (will skip this part is it may not be necessary for you, you can look at the logic for this on the EditorContainer)

Based on that the way I would recommend to do the autosave is:

Create an an EditorWrapper (HOC) the editors where you want auto save to be turned on

const editorWrapper(WrappedEditor) => {
    return class EditorWrapper extends Component {
       constructor(props) {
          base(props);
          this._changeCommitted = false;
          this.handleKeyDown.bind(this);
       }

       handleKeyDown({ key, stopPropagation }) {
          if (key === 'Tab' || key === 'Enter') {
             stopPropagation();
             this.save();
             this.props.onCommit({ key });
             this._changeCommitted = true;
          }
          // If you need the logic for the arrows too, check the editorContainer
       }

       save() {
          // Save logic.
       }

       hasEscapeBeenPressed() {
          let pressed = false;
          let escapeKey = 27;
          if (window.event) {
             if (window.event.keyCode === escapeKey) {
                pressed = true;
             } else if (window.event.which === escapeKey) {
               pressed  = true;
             } 
          }
          return pressed;
      }

       componentWillUnmount() {
          if (!this._changeCommitted && !this.hasEscapeBeenPressed()) {
             this.save();
          }
       }

       render() {
          return (
             <div onKeyDown={this.handleKeyDown}>
                <WrappedComponent {...this.props} />
             </div>);
       }
    }
}

When exporting you editor just wrap them with the EditorWrapper

const Editor = ({ name }) => <div>{ name }</div>

export default EditorWrapper(Editor);
Diogo Cunha
  • 1,194
  • 11
  • 23
0

Use one of the start or stop event callback handlers at the DataGrid level like onCellEditCommit

<DataGrid
    onCellEditCommit={({ id, field, value }, event) => {
      ...
    }
/>

or a valueSetter for a single the column definition:

const columns: GridColDef[] = [
  {
    valueSetter: (params: GridValueSetterParams) => {
      // params.row contains the current row model
      // params.value contains the entered value
    },
  },
];

<DataGrid columns={columns} />
Stefan Haberl
  • 9,812
  • 7
  • 72
  • 81